home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / sos3-2.lha / src / agg / Mapping_scp.c < prev    next >
C/C++ Source or Header  |  1992-01-23  |  127KB  |  2,770 lines

  1. #line 1 "/fzi/prost/stone/SOS3-2/src/agg/Mapping.c"
  2. /* --------------------------------------------------------------------------
  3.  * Copyright 1992 by Forschungszentrum Informatik (FZI)
  4.  *
  5.  * You can use and distribute this software under the terms of the licence
  6.  * you should have received along with this program.
  7.  * If not or if you want additional information, write to
  8.  * Forschungszentrum Informatik, "STONE", Haid-und-Neu-Strasse 10-14,
  9.  * D-7500 Karlsruhe 1, Germany.
  10.  * --------------------------------------------------------------------------
  11.  */
  12. // **************************************************************************
  13. // Module Mapping                   9/8/90                    Jochen Alt (ja)
  14. //                                                   modified : 24/10/91 (bs)
  15. //                                                   modified : 22/11/91 (ja)
  16. // **************************************************************************
  17. // implements methods of classes: Mapping, sos_Map_node
  18. // **************************************************************************
  19.  
  20. #include "agg_err.h"
  21. #include "trc_agg.h"
  22. #include "sys.h"
  23. #include "Mapping.h"
  24. #include "agg_sos.h"
  25.  
  26. // erweiterbares Hash-Verfahren mit leichten Modifikationen
  27. // Quelle : Datenbankhandbuch Seite 247
  28. // siehe externe Dokumentation
  29.  
  30. #define get_key_based_on_equal()  get_role1_based_on_equal()
  31. #define get_info_based_on_equal() get_role2_based_on_equal()
  32. #define set_key_based_on_equal(b)  set_role1_based_on_equal(b)
  33. #define set_info_based_on_equal(b) set_role2_based_on_equal(b)
  34.  
  35. inline int absolute(int d) { return (d>0)?d:-d; }
  36.  
  37. const sos_Offset NIL=0;
  38.  
  39. // Da psm direkt benutzt wird, wird ein Datentyp  benoetigt, der
  40. // anstelle der Objekte abgespeichert wird. Dies ist ein object_save_t,
  41. // der augenblicklich als sos_Typed_id definiert ist. Die beiden Operatoren,
  42. // die object_save_t in sos_Object und umgekehrt konvertieren, sind
  43. // make_object_save und make_Object
  44. // ************************************************************************** 
  45. object_save_t make_object_save (sos_Object o)
  46. // ************************************************************************** 
  47. // nimm das sos_Object o, bastle daraus ein object_save, und
  48. // liefere es in os zurueck
  49. {  sos_Typed_id  tpid = o.typed_id();
  50.    object_save_t os;
  51.    bcopy_from_sos_Typed_id(&tpid,&os);
  52.    return os;
  53.  
  54. // ************************************************************************** 
  55. sos_Object make_Object (object_save_t &os)
  56. // ************************************************************************** 
  57. // nimm den object_save os, mache daraus ein sos_Object und liefere es zurueck
  58. {  sos_Typed_id tpid;
  59.    bcopy_to_sos_Typed_id(&tpid,&os);
  60.    return sos_Object::make(tpid);
  61.  
  62. /*
  63. Abhaengig von sos_Bool:list_cursor gibt es zwei Versionen eines Mappings:
  64. 1. Version: list_cursor = FALSE
  65.    Die Cursoroperatoren sind nur auf einem statischen Mapping
  66.    definiert. Wird ein Objekt eingefuegt, so kan sich die Cursor-Reihenfolge
  67.    voellig veraendern. Damit ist ein sinnvoller Umgang mit Cursorn nur auf
  68.    einem sich nicht veraendernden Mapping moeglich. Sobald etwas eingefuegt 
  69.    oder geloescht wird, sind die Cursor zu schliessen und neu von vorne 
  70.    zu beginnen. Die Reihenfolge der Objekte ist durch die
  71.    Reihenfolge in der Hashtabelle definiert, also fuer den Benutzer rein
  72.    zufaellig. In dieser Version braucht ein Eintrag 36 Byte (= 2x sos_Object
  73.    und ein Hashwert a 4 byte)
  74. 2. Version : list_cursor = TRUE
  75.    Die Cursor-Operatoren koennen auch an einem dynamischen Mapping gleich-
  76.    zeitig ausgefuehrt werden. Die einzelnen Eintraege sind miteinander
  77.    doppelt verkettet, ein Einfuegen erfolgt am Anfang der Liste. Ein Eintrag
  78.    braucht damit 36+2x16 = 68 Byte (zusaetzlich ein Vorwaerts und ein 
  79.    Rueckwaertszeiger). Damit werden die Prozeduren remove_at, insert_before
  80.    und insert_after sinnvoll. In der Implementierung wird auf einer Seite
  81.    die struct-Komponente list, bestehend aus den beiden Verweisen 
  82.    zusaetzlich abgespeichert.
  83.  
  84. In Funktionen, die ein Objekt zurueckliefern sollen, jedoch keines zum Liefern 
  85. haben, wird my_no_object als Ruckgabeparameter von benutzt. Weiterhin dient 
  86. my_no_object als Ende-der-Liste Marke im ersten und letzten Element des 
  87. Mappings. Kurzum, my_no_object ist ein Mapping- lokales NO_OBJECT, und dient 
  88. dazu, das Einfuegen von NO_OBJECT zu ermoeglichen.  Stattdessen kann man eben 
  89. my_no_object nicht einfuegen. Faktisch wird my_no_object immer mit dem 
  90. augenblicklich benutzten Mapping initialisiert, so dass ein Mapping nicht in 
  91. sich selbst eingefuegt werden kann. Dieses wird entsprechend abgefangen.
  92. */
  93.  
  94. #define PAGE_SIZE(list_cursor) \
  95.    (list_cursor?page_size_with_list: page_size_without_list)
  96.  
  97. // max_page_entries = die maximale Anzahl an Eintraegen auf einer Seite
  98. #define MAX_PAGE_ENTRIES(list_cursor) \
  99.    (list_cursor? max_page_entries_with_list: max_page_entries_without_list)
  100.  
  101. // aus einer gegebenen Position in der Hashtabelle und der lokalen Tiefe
  102. // der zugehoerigen Seitenliste kann die erste Position in der Hashtabelle
  103. // berechnet werden, die auf diesselbe Seitenliste zeigt.
  104. #define FIRST_LINK(ht_pos,local_depth) \
  105.    ((LSHIFT(1,local_depth)-1) BITAND ht_pos)
  106.  
  107. /* ***********    Implementierung von sos_Map_node    *********************
  108. Ein sos_Map_node enthaelt nur die Komponente sos_Object:key_val, die 
  109. dasjenige Objekt angibt, auf das der Cursor augenblicklich zeigt. 
  110. Ein sos_Map_node ist eindeutig einem Cursor zugeordnet und liegt 
  111. in dessen Container. Ist der Cursor ungueltig, so ist die Komponente 
  112. Cursor->get_key_val() == NO_OBJECT, andernfalls zeigt sie auf einen 
  113. sos_Map_node. Also wird beim Starten auf einem Mapping mit Inhalt ein 
  114. sos_Map_node erzeugt und dem Cursor zugeordnet, beim Verlassen des 
  115. letzten gueltigen Elements wird der sos_Map_node wieder geloescht.
  116. */
  117.  
  118.  
  119. // ************************************************************************** 
  120. sos_Int hash_id (sos_Object o)
  121. // ************************************************************************** 
  122. // benutzt die Adresse des Objektes, um daraus eine Zahl zu basteln
  123.  
  124. // Offsets liegen  nur auf durch 8 teilbaren Addressen
  125. // => die ersten 3 Bit sind nutzlos, wird sie weg.
  126. // Ist das Objekt aber keine Klassen-Instanz, sondern 
  127. // ein externes Objekt (z.B. sos_Int,sos_Char),
  128. // so wird der Offset benutzt, indem der Wert steht.
  129. {  sos_Int h = o.offset();
  130.    if (o.container() != UNUSED_CONTAINER)
  131.       h = RSHIFT(h,3) BITXOR sos_Int(o.container());
  132.     
  133.    return h;
  134. } // ** hash_id **
  135.  
  136.  
  137. // ************************************************************************** 
  138. ht_entry_t read_ht_entry(sos_Container ct, 
  139.                          sos_Offset ht_offset, 
  140.                          sos_Int ht_pos)
  141. // ************************************************************************** 
  142. {  union {sos_Offset dummy;
  143.       char       mem [HT_ENTRY_SIZE];} u;
  144.    ct.read(ht_offset+ht_pos*HT_ENTRY_SIZE, HT_ENTRY_SIZE, &u);
  145.    ht_entry_t ht_entry;
  146.    bcopy_to_sos_Offset(&ht_entry.page_list_offset,&u.mem[0]);
  147.    bcopy_to_sos_Char(&ht_entry.local_depth, &u.mem[SOS_OFFSET_SIZE] );
  148.    return ht_entry;
  149. } // ** read_ht_entry **
  150.  
  151. // ************************************************************************** 
  152. void write_ht_entry(sos_Container ct, 
  153.                     sos_Offset ht_offset, 
  154.                     sos_Int ht_pos, 
  155.                     ht_entry_t ht_entry)
  156. // ************************************************************************** 
  157. {  union {sos_Offset dummy;
  158.       char       mem [HT_ENTRY_SIZE];} u;
  159.  
  160.    bcopy_from_sos_Offset(&ht_entry.page_list_offset, &u.mem[0]);
  161.    bcopy_from_sos_Char(&ht_entry.local_depth, &u.mem[SOS_OFFSET_SIZE]);
  162.    ct.write(ht_offset+ht_pos*HT_ENTRY_SIZE, HT_ENTRY_SIZE, &u);
  163. } // ** write_ht_entry **
  164.  
  165.  
  166. // ************************************************************************** 
  167. page_header_t  read_page_header(sos_Container ct, sos_Offset page_offset) 
  168. // ************************************************************************** 
  169. {  union {sos_Offset dummy;
  170.       char       mem [PAGE_HEADER_SIZE];} u;
  171.  
  172.    page_header_t page_header;
  173.    ct.read (page_offset, PAGE_HEADER_SIZE, &u);
  174.    bcopy_to_sos_Offset(&page_header.next_page, &u.mem[0]);
  175.    bcopy_to_sos_Char(&page_header.pages, &u.mem[SOS_OFFSET_SIZE]);
  176.    bcopy_to_sos_Char(&page_header.entries_on_last_page,
  177.              &u.mem[SOS_OFFSET_SIZE+CHAR_SIZE]);
  178.  
  179.    return page_header;
  180. } // ** read_page_header **
  181.  
  182. // ************************************************************************** 
  183. void write_page_header(sos_Container ct,
  184.                        sos_Offset page_offset, 
  185.                        page_header_t& page_header)
  186. // ************************************************************************** 
  187. {  union {sos_Offset dummy;
  188.       char       mem [PAGE_HEADER_SIZE];} u;
  189.  
  190.    bcopy_from_sos_Offset(&page_header.next_page,&u.mem[0]);
  191.    bcopy_from_sos_Char(&page_header.pages,&u.mem[SOS_OFFSET_SIZE]);
  192.    bcopy_from_sos_Char(&page_header.entries_on_last_page,
  193.                &u.mem[SOS_OFFSET_SIZE+CHAR_SIZE]);
  194.    ct.write (page_offset, PAGE_HEADER_SIZE, &u);
  195. } // ** write_page_header **
  196.  
  197.  
  198. /*
  199. Eine Seitenliste besteht aus einzelnen Seiten des Typs page_t, wobei 
  200. diese durch Vorwaertszeiger verkettet sind. Auf jeder Seite befindet sich 
  201. ein Seitenkopf mit den Angaben:
  202.  
  203.         sos_Char       pages; 
  204.            => Anzahl der Seiten in der Seitenliste
  205.         sos_Char       entries_on_last_page;
  206.            => Eintraege auf der letzten Seite, alle anderen Seite sind
  207.               voll, d.h. sie haben max_page_entries Eintraege. Diese Angabe
  208.               wird nur auf der ersten Seite verwaltet, auf den restlichen
  209.               Seiten ist entries_on_last_page undefiniert.
  210.         sos_Offset next_page;
  211.            => Verweis auf die naechste Seite, bei der letzten Seite 
  212.               undefiniert.
  213. */
  214.  
  215.  
  216. // ************************************************************************** 
  217. void destroy_page_list(sos_Bool      list_cursor,
  218.                        sos_Container ct, 
  219.                        sos_Offset    page_offset,
  220.                        sos_Int       no_of_pages)
  221. // ************************************************************************** 
  222. // deallokiere im Container ct die Seitenliste bestehend aus den
  223. // Typen page_t, wobei die erste zu deallokierende Seite auf page_offset 
  224. // liegt. Insgesamt sind no_of_pages Seiten  zu loeschen.
  225. {  sos_Offset act_page_offset = page_offset;
  226.    sos_Offset next_page_offset;
  227.    for (sos_Int i=1;i<=no_of_pages;i++)
  228.    {     // Lese zuerst naechsten Verweis, bevor die Seite deallokiert wird
  229.       page_header_t page_header = read_page_header(ct, act_page_offset);
  230.       next_page_offset = page_header.next_page;
  231.       
  232.       ct.deallocate(act_page_offset,PAGE_SIZE(list_cursor));
  233.       act_page_offset = next_page_offset;
  234.    } 
  235. } // ** destroy_page_list **
  236.  
  237.  
  238. // ************************************************************************** 
  239. void read_page( sos_Bool      list_cursor,
  240.                 sos_Container ct,
  241.                 sos_Offset    page_offset, 
  242.                 sos_Int       no_of_entries, 
  243.                 page_t&       page)
  244. // ************************************************************************** 
  245. // Lese Seite ab sos_Offset page_offset. Es werden no_of_entries
  246. // Eintraege eingelesen.
  247. {  err_assert((no_of_entries>=0 AND no_of_entries<=MAX_PAGE_ENTRIES(list_cursor)),
  248.       "Mapping:read_page_entry::internal Error");
  249.    page.page_header = read_page_header(ct,page_offset);
  250.    union {sos_Typed_id dummy;
  251.       char         mem [MAX_PAGE_SIZE];} u;
  252.    ct.read(page_offset+PAGE_HEADER_SIZE, no_of_entries*ENTRY_SIZE,&u);
  253.    char *ptr = u.mem;
  254.    for (int i = 0;i<no_of_entries;i++)
  255.    {  bcopy_to_sos_Typed_id(&page.entry[i].key,ptr);
  256.       ptr += SOS_TYPED_ID_SIZE;
  257.       bcopy_to_sos_Typed_id(&page.entry[i].info,ptr);
  258.       ptr += SOS_TYPED_ID_SIZE;
  259.       bcopy_to_sos_Int(&page.entry[i].hash_value,ptr);
  260.       ptr += INT_SIZE;
  261.    } 
  262.  
  263.    if (list_cursor)
  264.    {     // Lese die Vorgaenger und Nachfolger Verweise
  265.       ptr = u.mem;
  266.       ct.read(page_offset+add_list_pos, no_of_entries*LIST_SIZE, &u);
  267.       for (int i = 0; i < no_of_entries; i++)
  268.       {  bcopy_to_sos_Typed_id(&page.list[i].pred,ptr);
  269.          ptr += SOS_TYPED_ID_SIZE;
  270.          bcopy_to_sos_Typed_id(&page.list[i].succ,ptr);
  271.          ptr += SOS_TYPED_ID_SIZE;
  272.       } 
  273.    }
  274. } // ** read_page **
  275.  
  276. // ************************************************************************** 
  277. sos_Int read_page( sos_Bool      list_cursor,
  278.                    sos_Container ct,
  279.                    page_header_t first_page_header, 
  280.                    ht_entry_t    ht_entry, 
  281.                    sos_Int       page_no, 
  282.                    page_t&       page)
  283. // ************************************************************************** 
  284. // Lese die page_no.te Seite, auf die der Hashtabelleneintrag ht_entry
  285. // zeigt, wobei der Seitenkopf der ersten Seite schon unter 
  286. // first_page_header bekannt ist.
  287. {  sos_Offset page_offset = ht_entry.page_list_offset;
  288.    page.page_header = first_page_header;
  289.  
  290.       // Durchlaufe Seitenliste bis zur richtigen Seite
  291.    for (sos_Int no = 1; no < page_no; no++)
  292.    { if (no >1)
  293.          page.page_header = read_page_header(ct,page_offset);
  294.       page_offset =page.page_header.next_page;
  295.    } 
  296.    sos_Int entries = (page_no < first_page_header.pages)?
  297.                      MAX_PAGE_ENTRIES(list_cursor):
  298.                      first_page_header.entries_on_last_page;
  299.    read_page(list_cursor, ct, page_offset, entries, page);
  300.  
  301.    return entries;
  302. } // ** read_page **
  303.  
  304. // ************************************************************************** 
  305. void read_page_entry(sos_Bool      list_cursor,
  306.                      sos_Container ct,
  307.                      sos_Int       page_offset, 
  308.                      sos_Int       entry_no, 
  309.                      page_t&       page)
  310. // ************************************************************************** 
  311. // Lese auf der Seite auf page_offset den entry_no.ten Eintrag in page
  312. {  err_assert((entry_no>=0 AND entry_no<=MAX_PAGE_ENTRIES(list_cursor)),
  313.       "Mapping::read_page_entry::internal Error");
  314.    union {sos_Typed_id dummy;
  315.       char         mem[ENTRY_SIZE];} u; // note: ENTY_SIZE > LIST_SIZE
  316.  
  317.    ct.read( page_offset+PAGE_HEADER_SIZE+entry_no*ENTRY_SIZE,
  318.             ENTRY_SIZE,&u);
  319.    bcopy_to_sos_Typed_id(&page.entry[entry_no].key,&u.mem[0]);
  320.    bcopy_to_sos_Typed_id(&page.entry[entry_no].info,&u.mem[SOS_TYPED_ID_SIZE]);
  321.    bcopy_to_sos_Int(&page.entry[entry_no].hash_value,
  322.             &u.mem[SOS_TYPED_ID_SIZE+SOS_TYPED_ID_SIZE]);
  323.  
  324.    if (list_cursor)
  325.    {  ct.read( page_offset+add_list_pos+entry_no*LIST_SIZE,
  326.                LIST_SIZE,&u);
  327.       bcopy_to_sos_Typed_id(&page.list[entry_no].pred,&u.mem[0]);
  328.       bcopy_to_sos_Typed_id(&page.list[entry_no].succ,
  329.                             &u.mem[SOS_TYPED_ID_SIZE]);
  330.    }
  331. } // ** read_page_entry **
  332.  
  333. // ************************************************************************** 
  334. void write_page(sos_Bool      list_cursor,
  335.                 sos_Container ct, 
  336.                 sos_Offset    page_offset,
  337.                 sos_Int       no_of_entries, 
  338.                 page_t&       page)
  339. // ************************************************************************** 
  340. // Schreibe die Seite page mit no_of_entries Eintraegen 
  341. // an die Stelle page_offset
  342. {  write_page_header(ct,page_offset,page.page_header);
  343.    err_assert((no_of_entries>=0 AND no_of_entries<=MAX_PAGE_ENTRIES(list_cursor)),
  344.       "Mapping::write_page::internal Error");
  345.  
  346.    union {sos_Typed_id dummy;
  347.       char           mem [MAX_PAGE_SIZE];} u;
  348.    char *ptr = u.mem;
  349.    for (int i = 0; i < no_of_entries; i++)
  350.    {  bcopy_from_sos_Typed_id(&page.entry[i].key,ptr);
  351.       ptr += SOS_TYPED_ID_SIZE;
  352.       bcopy_from_sos_Typed_id(&page.entry[i].info,ptr);
  353.       ptr += SOS_TYPED_ID_SIZE;
  354.       bcopy_from_sos_Int(&page.entry[i].hash_value,ptr);
  355.       ptr += INT_SIZE;
  356.    } 
  357.    ct.write(page_offset+PAGE_HEADER_SIZE, no_of_entries*ENTRY_SIZE,&u);
  358.  
  359.    if (list_cursor)
  360.    {  ptr = u.mem;
  361.       for (int i = 0; i < no_of_entries; i++)
  362.       {  bcopy_from_sos_Typed_id(&page.list[i].pred,ptr);
  363.          ptr += SOS_TYPED_ID_SIZE;
  364.          bcopy_from_sos_Typed_id(&page.list[i].succ,ptr);
  365.          ptr += SOS_TYPED_ID_SIZE;
  366.       }
  367.       ct.write(page_offset+add_list_pos, LIST_SIZE*no_of_entries, &u);
  368.    }
  369. } // ** write_page **
  370.  
  371. // ************************************************************************** 
  372. void write_page_entry(sos_Bool      list_cursor,
  373.                       sos_Container ct, 
  374.                       sos_Int       page_offset, 
  375.                       sos_Int       entry_no, 
  376.                       page_t&       page)
  377. // ************************************************************************** 
  378. // Schreibe auf der Seite page den einzelnen Eintrag Nr entry_no
  379. // auf die Platte, der Seitenanfang beginnt bei page_offset.
  380. {  err_assert((entry_no>=0 AND entry_no<=MAX_PAGE_ENTRIES(list_cursor)),
  381.       "Mapping::write_page::internal Error");
  382.    union {sos_Typed_id dummy;
  383.       char         mem[ENTRY_SIZE];} u; // note: ENTY_SIZE > LIST_SIZE
  384.  
  385.    bcopy_from_sos_Typed_id(&page.entry[entry_no].key,&u.mem[0]);
  386.    bcopy_from_sos_Typed_id(&page.entry[entry_no].info,
  387.                            &u.mem[SOS_TYPED_ID_SIZE]);
  388.    bcopy_from_sos_Int(&page.entry[entry_no].hash_value,
  389.               &u.mem[SOS_TYPED_ID_SIZE+SOS_TYPED_ID_SIZE]);
  390.  
  391.    ct.write( page_offset+PAGE_HEADER_SIZE+entry_no*ENTRY_SIZE,
  392.              ENTRY_SIZE,&u);
  393.    if (list_cursor)
  394.    {  bcopy_from_sos_Typed_id(&page.list[entry_no].pred,&u.mem[0]);
  395.       bcopy_from_sos_Typed_id(&page.list[entry_no].succ,
  396.                               &u.mem[SOS_TYPED_ID_SIZE]);
  397.       ct.write( page_offset+add_list_pos+entry_no*LIST_SIZE, LIST_SIZE,&u);
  398.    }   
  399. } // ** write_page_entry **
  400.  
  401. // search_page_for_key__F8sos_BoolR6page_tiiG10sos_Object
  402. // ************************************************************************** 
  403. sos_Int search_page_for_key(sos_Bool     key_based_on_equal, 
  404.                             page_t&      page, 
  405.                             sos_Int      entries, 
  406.                             sos_Int      org_hash_value, 
  407.                             sos_Object   key)
  408. // ************************************************************************** 
  409. // durchsucht die Seite page mit entries Eintraegen nach dem sos_Object key,
  410. // das den Hashwert org_hash_value besitzt. Wird es gefunden, wird seine
  411. // Position in der Seite geliefert, ansonsten -1.
  412. {  T_PROC("search_page_for_key");
  413.    TT(agg_M, T_ENTER);
  414.  
  415.    sos_Bool found = FALSE;
  416.    for (sos_Int i=0;
  417.         ((i<entries) AND (NOT found));
  418.         i++)
  419.    {  if (page.entry[i].hash_value == org_hash_value)
  420.       {  sos_Object o = make_Object(page.entry[i].key);
  421.          if (agg_same_entity(o, key, key_based_on_equal, EQ_STRONG))
  422.          {  found = TRUE;
  423.             TT(agg_M, T_LEAVE);
  424.             return i;
  425.          }
  426.       }
  427.    } 
  428.  
  429.    TT(agg_M, T_LEAVE);
  430.    return -1;
  431. } // ** search_page_for_key **
  432.  
  433. // ************************************************************************** 
  434. sos_Offset new_page_list(sos_Container ct, sos_Bool list_cursor)
  435. // ************************************************************************** 
  436. // allokiere eine neue Seitenliste und liefere deren sos_Offset zurueck
  437. {  T_PROC("new_page_list");
  438.    TT(agg_L, T_ENTER);
  439.  
  440.    sos_Offset new_page_offset = ct.allocate(PAGE_SIZE(list_cursor));
  441.    page_header_t page_header;
  442.    page_header.entries_on_last_page = 0;
  443.    page_header.pages = 1;
  444.    write_page_header(ct,new_page_offset, page_header);
  445.  
  446.    TT(agg_L, T_LEAVE);
  447.    return new_page_offset;
  448. } // ** new_page_list **
  449.  
  450. // ************************************************************************** 
  451. void _sos_Object_sos_Object_Mapping::write_succ_pred(
  452.                                       sos_Typed_id &_tpid,sos_Container ct,
  453.                                       sos_Bool      key_based_on_equal,
  454.                                       sos_Bool      list_cursor,
  455.                                       sos_Object    key, 
  456.                                       sos_Bool      write_succ, 
  457.                                       sos_Object    succ_pred)
  458. // ************************************************************************** 
  459. // Schreibe in den Vorgaeger bzw. Nachfolger von key succ_pred.
  460. // Ob Vor oder Nachgaenger ausgewaehlt wird, wird durch write_succ 
  461. // geregelt. write_succ == TRUE schreibt succ_pred in den 
  462. // Nachfolgerzeiger von key, ansonsten in den Vorgaengerzeiger von key.
  463. {  T_PROC("Mapping::write_succ_pred");
  464.    TT(agg_M, T_ENTER);
  465.    sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  466.    if (my_no_object == key)
  467.    {  TT(agg_M, T_LEAVE);
  468.       return;
  469.    }
  470.    
  471.    sos_Int org_hash_value = absolute((key_based_on_equal)?
  472.                                       key.hash_value():hash_id(key));
  473.    sos_Int ht_pos = org_hash_value MOD sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  474.    ht_entry_t ht_entry = read_ht_entry(ct,sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),ht_pos);
  475.  
  476.    sos_Offset page_offset = ht_entry.page_list_offset;
  477.    page_header_t first_page_header = read_page_header(ct, page_offset);
  478.    sos_Int pages = first_page_header.pages;
  479.    sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
  480.  
  481.    sos_Int pos = -1; // entspricht "nicht gefunden"
  482.    sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  483.    page_t page;
  484.    for (sos_Int page_no = 1;
  485.         (page_no<=pages) AND (pos == -1);
  486.         page_no++)
  487.    {  if (page_no == pages)
  488.      entries_on_page = entries_on_last_page;
  489.  
  490.       read_page(TRUE, ct, page_offset, entries_on_page, page);
  491.       sos_Int pos = search_page_for_key ( key_based_on_equal,page, 
  492.                                           entries_on_page,
  493.                                           org_hash_value, key );
  494.       if (pos == -1)
  495.          page_offset = page.page_header.next_page;
  496.       else
  497.       {     // Objekt gefunden
  498.          if (write_succ)
  499.             page.list[pos].succ = make_object_save(succ_pred);
  500.          else
  501.             page.list[pos].pred = make_object_save(succ_pred);
  502.          write_page_entry(TRUE, ct,page_offset,pos, page);
  503.       }
  504.    } 
  505.    TT(agg_M, T_LEAVE);
  506. } // ** Mapping::write_succ_pred **
  507.  
  508.  
  509. // ************************************************************************** 
  510. sos_Offset increase_page_list( sos_Bool       list_cursor,
  511.                                sos_Container  ct, 
  512.                                sos_Offset     first_page_offset,
  513.                                page_header_t& first_page_header,
  514.                                sos_Offset     last_page_offset)
  515. // ************************************************************************** 
  516. // Eine Seitenliste, die an der Stelle ht_pos an der Hashtabelle
  517. // angehaengt ist, wird um eine Seite erweitert. diese Seite wird
  518. // hinten angehaengt. Ein Verweis auf die bisher letzte Seite 
  519. {  T_PROC("increase_page_list");
  520.    TT(agg_M, T_ENTER);
  521.  
  522.    sos_Offset new_page_offset = ct.allocate(PAGE_SIZE(list_cursor));
  523.  
  524.       // Eigentlich sollte der Fall der Seitenlisten gaenzlich vermieden
  525.       // werden. Wird nun eine Seitenliste tatsaechlich ueber 126 Seiten
  526.       // gross, so ist entweder die Statistik fehlerhaft, oder es
  527.       // sind tatsaechlich mehr als 3225 Eintraege mit demselben Hashwert im
  528.       // Mapping. Diese Faelle fuehren zum Absturz, da die Variable, die die
  529.       // Seiten in einer Seitenliste zaehlt, ein char ist. Ansich ist eine
  530.       // solche Konstellation jedoch nicht vorstellbar.
  531.    if (first_page_header.pages >= 126)
  532.       err_raise(err_SYS, "statistical Error","Mapping:insert");
  533.  
  534.    first_page_header.pages++;
  535.    first_page_header.entries_on_last_page = 0;
  536.   
  537.       // Existierte bisher nur eine Seite ?
  538.    if (first_page_header.pages == 2)
  539.       first_page_header.next_page = new_page_offset;
  540.    else
  541.    {     // Es gab schon mehr als eine Seite, der erste Seitenheader und 
  542.          // der Header der bisher letzten Seite muss geschrieben werden
  543.       page_header_t last_page_header;
  544.       last_page_header.next_page = new_page_offset;
  545.       write_page_header(ct,last_page_offset, last_page_header);
  546.    }
  547.    write_page_header(ct,first_page_offset, first_page_header);
  548.  
  549.    TT(agg_M, T_LEAVE);
  550.    return new_page_offset;
  551. } // ** Mapping::increase_page_list
  552.  
  553. /*
  554. Um zu entscheiden, ob die Hashtabelle geschrumpft werden kann, muss bekannt 
  555. sein, ob es Seitenlisten gibt, auf die nur ein HT-Eintrag verweist. Falls ja,
  556. ist ein Schrumpfen nicht moeglich. Da beim Teilen und Splitten einer Seite
  557. die lokale Tiefe veraendert wird, muss fuer jede moegliche lokale Tiefe 
  558. die Anzahl der Verweise gespeichert werden, da beim Splitten 2 Seiten
  559. mit hoeheren lokalen Tiefen dazukommen und eine mit einer niedrigeren weg-
  560. faellt. 
  561. Es gibt also einen von Hand allokierten Platz, auf dessen Anfang 
  562. get_no_of_pages_offset() zeigt. In den ersten 4 Byte davon steht die Anzahl 
  563. der Seitenlisten mit lokaler Tiefe 0 , in den naechsten 4 Byte die Anzahl mit
  564. lokaler Tiefe 1 etc. bis MAX_GLOBAL_DEPTH.
  565. */
  566.  
  567. // ************************************************************************** 
  568. sos_Bool no_single_referenced_pages(sos_Container ct, 
  569.                                     sos_Offset    no_of_pages_offset, 
  570.                                     sos_Int       global_depth)
  571. // ************************************************************************** 
  572. // liefert TRUE, falls es keine Seitenliste gibt, die von der Hashtabelle
  573. // nur von einem einzigen Verweis referenziert wird. Dies wird anhand
  574. // der Zaehler festgestellt, die fuer jede lokale Tiefe zaehlen, wieviel
  575. // Seitenlisten es mit dieser lokalen Tiefe gibt. Die Seitenlisten,  die
  576. // nur von einem Verweis referenziert werden, zeichnen sich durch  
  577. // lokale Tiefe == globale Tiefe aus.
  578. {  sos_Int entry;
  579.    union {sos_Int dummy;
  580.       char    mem [INT_SIZE];} u;
  581.       // lese die Anzahl der Verweise auf Seitenlisten der lokalen 
  582.       // Tiefe global_depth
  583.    ct.read(no_of_pages_offset+INT_SIZE*global_depth,INT_SIZE,&u);
  584.    bcopy_to_sos_Int(&entry,&u); 
  585.    return sos_Bool (entry == 0);
  586. } // ** Mapping::no_single_referenced_pages **
  587.  
  588. // ************************************************************************** 
  589. void add_no_of_pages(sos_Container ct, 
  590.                      sos_Offset    no_of_pages_offset, 
  591.                      sos_Int       local_depth, 
  592.                      sos_Int       value)
  593. // ************************************************************************** 
  594. // zaehle zu der Anzahl von Verweisen auf eine Seitenliste mit der
  595. // lokalen Tiefe local_depth value dazu.
  596. {  sos_Int entry;
  597.    union {sos_Int dummy;
  598.       char    mem [INT_SIZE];} u;
  599.  
  600.    sos_Int offset = no_of_pages_offset+INT_SIZE*local_depth;
  601.    ct.read(offset, INT_SIZE, &u);
  602.    bcopy_to_sos_Int(&entry,&u);
  603.    entry += value;
  604.    bcopy_from_sos_Int(&entry,&u);
  605.    ct.write(offset, INT_SIZE, &u);
  606. } // ** add_no_of_page **
  607.  
  608.  
  609. // ************************************************************************** 
  610. void _sos_Object_sos_Object_Mapping::insert_in_page_list (
  611.                                         sos_Typed_id &_tpid,sos_Container ct,
  612.                                         sos_Bool      key_based_on_equal,
  613.                                         sos_Bool      list_cursor,
  614.                                         sos_Offset    page_list_offset, 
  615.                                         sos_Int       org_hash_value, 
  616.                                         sos_Object key, sos_Object info,
  617.                                         sos_Object pred, sos_Object succ)
  618. // ************************************************************************** 
  619. // traegt einen Eintrag in eine Seitenliste ein und ersetzt
  620. // geg. einen alten. Auf der Seitenliste muss Platz sein
  621. {  T_PROC("Mapping::insert_in_page_list");
  622.  
  623.    page_t page;
  624.    sos_Offset page_offset = page_list_offset;
  625.    
  626.       // Befindet sich der key bereits auf der Seite, so wird er durch
  627.       // den neuen Eintrag ersetzt. Schaue also nach
  628.    
  629.    sos_Int pos = -1; // entspricht "nicht gefunden"
  630.    sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  631.  
  632.    page.page_header = read_page_header(ct,page_offset);
  633.  
  634.    page_header_t first_page_header = page.page_header;
  635.    sos_Int pages = first_page_header.pages;
  636.    sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
  637.    for (sos_Int page_no=1; 
  638.         (page_no <= pages) AND (pos == -1); 
  639.         page_no++)
  640.    {  if (page_no == pages)
  641.      entries_on_page = entries_on_last_page;
  642.       read_page(list_cursor, ct,page_offset, entries_on_page, page);
  643.       pos = search_page_for_key (key_based_on_equal, page, 
  644.                                  entries_on_page, org_hash_value,key);
  645.       if ((pos == -1) AND (page_no < pages))
  646.          page_offset = page.page_header.next_page;
  647.    } 
  648.  
  649.       // Falls der Eintrag ersetzt wird, so wird er an diese
  650.       // Stelle eingesetzt. Ansonsten wird er auf der
  651.       // letzten Seite eingetragen und die H-Tabelle korrigiert
  652.  
  653.    sos_Int write_pos = pos;
  654.    if (pos == -1)
  655.    {     // Eintrag nicht gefunden, also schreibe ihn auf die letzte Seite.
  656.          // Da die gesamte Liste durchgegangen wurde, ist page_offset
  657.          // die Adresse der letzten Seite.
  658.       
  659.          // korrigiere Seitenheader der ersten Seite
  660.       first_page_header.entries_on_last_page++;
  661.       write_page_header(ct,page_list_offset,first_page_header);
  662.  
  663.       write_pos = entries_on_page;
  664.       sos_Object_sos_Object_Mapping::make(_tpid,this).set_cardinality(sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality() + 1);
  665.    }
  666.  
  667.    page.entry[write_pos].hash_value = org_hash_value;
  668.       // Falls der Key existiert wird er nicht nochmal eingetragen,
  669.       // sondern nur der Entity ersetzt
  670.    if (write_pos != pos)
  671.       page.entry[write_pos].key = make_object_save(key);
  672.    page.entry[write_pos].info = make_object_save(info);
  673.  
  674.       // Schreibe die Liste evt auf die Seite zurueck
  675.    if (pos == -1)
  676.    {  if (list_cursor)
  677.       {     // schreibe in die Liste succ und pred
  678.          page.list[write_pos].succ = make_object_save(succ);
  679.          page.list[write_pos].pred = make_object_save(pred);
  680.             // aktualisiere den Vorwaertszeiger von pred und den 
  681.             // Rueckwaertszeiger von succ
  682.          sos_Object_sos_Object_Mapping::make(_tpid,this).write_succ_pred
  683.             (ct, key_based_on_equal, list_cursor, pred, TRUE, key);
  684.          sos_Object_sos_Object_Mapping::make(_tpid,this).write_succ_pred
  685.             (ct, key_based_on_equal, list_cursor, succ, FALSE, key);
  686.  
  687.          if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality() == 1)
  688.          {     // erstes Element wird eingefuegt
  689.             sos_Object_sos_Object_Mapping::make(_tpid,this).set_first_object(key);
  690.             sos_Object_sos_Object_Mapping::make(_tpid,this).set_last_object(key);
  691.          }
  692.          else
  693.          {  if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_first_object() == succ)
  694.                sos_Object_sos_Object_Mapping::make(_tpid,this).set_first_object(key);
  695.             if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_last_object() == pred)
  696.                sos_Object_sos_Object_Mapping::make(_tpid,this).set_last_object(key);
  697.          }
  698.       }
  699.  
  700.          // schreibe den Eintrag auf der Seite zurueck
  701.       write_page_entry(list_cursor, ct,page_offset, write_pos, page);
  702.    }
  703.    else
  704.          // Der Eintrag war bereits vorhanden, nur der Entity wurde geaendert
  705.          // schreibe den Eintrag auf der Seite zurueck
  706.       write_page_entry(list_cursor, ct,page_offset, write_pos, page);
  707.  
  708.    TT(agg_M, T_LEAVE);
  709. } // ** Mapping::insert_in_page_list **
  710.  
  711.  
  712.  
  713. // ************************************************************************** 
  714. void _sos_Object_sos_Object_Mapping::split_page(sos_Typed_id &_tpid,sos_Container ct, 
  715.                                                sos_Bool      list_cursor, 
  716.                                                sos_Offset    page_list_offset,
  717.                                                sos_Char      par_local_depth,
  718.                                                sos_Int       org_hash_value, 
  719.                                                sos_Int       nec_local_depth)
  720. // ************************************************************************** 
  721. // Eine Seitenliste wird solange gesplittet, bis der Seitenliste
  722. // die neue lokale Tiefe nec(cessary)_local_depth zugeordnet wird.
  723. // Saemtliche Seitenteilungen vor der letzten sind Seitenteilungen
  724. // ohne Bewegungen von Objekten, denn wuerden Objekte bewegt,
  725. // wuerde Platz geschaffen und somit waere nec_local_depth kleiner.
  726. {  T_PROC("Mapping::split_page");
  727.    TT(agg_M, T_ENTER);
  728.  
  729.    sos_Int global_depth = sos_Object_sos_Object_Mapping::make(_tpid,this).get_global_depth();
  730.    sos_Offset no_of_pages_offset = sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages_offset();
  731.    sos_Offset ht_offset = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset();
  732.  
  733.    sos_Int max_page_entries = MAX_PAGE_ENTRIES(list_cursor);
  734.       // Teile die Seitenliste sooft wie noetig, d.h. allokiere neue
  735.       // Seiten und biege die richtigen HT-Eintraege auf diese
  736.       // Seiten um
  737.    for (;par_local_depth <nec_local_depth;)
  738.    {     // erzeuge neue leere Seite
  739.       ht_entry_t new_ht_entry;
  740.       new_ht_entry.page_list_offset = new_page_list(ct, list_cursor);
  741.       sos_Int local_depth           = par_local_depth;
  742.       sos_Int new_local_depth       = ++par_local_depth;
  743.       new_ht_entry.local_depth      = new_local_depth;
  744.       sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_page_lists(sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_page_lists() + 1);
  745.       sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages() + 1);
  746.  
  747.       add_no_of_pages(ct,no_of_pages_offset,local_depth,-1);
  748.       add_no_of_pages(ct,no_of_pages_offset,new_local_depth,2);
  749.  
  750.          // biege alle Eintraege der HT mit gesetztem
  751.          // new_local_depth.ten Bit auf die neue Seite um
  752.  
  753.          // Wie lautet der der neuen Seite zugeordnete Hash-Wert-Teil ?
  754.          // Nimm den alten Hash-Teil
  755.       sos_Int old_hash_value_part = org_hash_value BITAND 
  756.                                     (LSHIFT(1,local_depth)-1); 
  757.  
  758.          // Laufe alle Indexe durch, bei denen ein Verweis
  759.          // auf die zu teilende Seitenliste steht. Das sind
  760.          // 2^(global_depth-local_depth) Stueck.
  761.  
  762.          // Die Verweise werden abwechselnd belassen und umgebogen.
  763.          // Da auf der alten Seitenliste die ersten nec_local_depth
  764.          // Bit gleich sind, wird so begonnen, dass die alte Seitenliste
  765.          // immer noch von der gleichen Stelle der 
  766.          // H-Tabelle erreicht wird (new_link)
  767.       sos_Bool new_link = FALSE; // starte bei alter Seitenliste
  768.       if ((org_hash_value BITAND LSHIFT(1,local_depth)) != 0)
  769.          new_link = TRUE; // starte bei leerer Seite
  770.  
  771.          // wo ist der erste Verweis auf diese Seitenliste ?
  772.       for (sos_Int k = 0;k<LSHIFT(1,global_depth-local_depth); k++)
  773.       {     // verschiebe Laufindex k an richtige Position 
  774.             // vor dem Wert der Seite
  775.          sos_Int j = LSHIFT(k,local_depth);
  776.             // addiere den Hash-Teil der Seite dazu
  777.          j = j BITOR old_hash_value_part;
  778.          
  779.          if (new_link)
  780.                // Dieser Eintrag muss auf die neue 
  781.                // leere Seite umgebogen werden
  782.             write_ht_entry(ct, ht_offset, j, new_ht_entry);
  783.          else
  784.          {     // Dieser Eintrag verbleibt,
  785.                // lediglich die lokale Tiefe wird geaendert
  786.             ht_entry_t tmp_ht_entry = read_ht_entry(ct, ht_offset, j);
  787.             tmp_ht_entry.local_depth ++;
  788.             write_ht_entry(ct,ht_offset,j, tmp_ht_entry);
  789.          }
  790.          new_link = (sos_Bool) (NOT new_link);
  791.       } 
  792.    } 
  793.  
  794.       // Da nur die letzte Seitenteilung hierbei beteiligt ist,
  795.       // muessen also Seiteneintraege der alten Seitenliste 
  796.       // auf die bis jetzt leere Partnerseite. 
  797.       // Berechne Hash-Teil der alten Seitenliste
  798.    sos_Int hash_value_part = org_hash_value BITAND 
  799.                              (LSHIFT(1,nec_local_depth)-1);
  800.       // invertiere das nec_local_depth.te Bit => Partnerseite 
  801.    sos_Int ht_partner_pos = hash_value_part BITXOR 
  802.                             LSHIFT(1,nec_local_depth-1);
  803.    
  804.       // Lese den Offset der Partnerseite
  805.    ht_entry_t ht_partner_entry = read_ht_entry(ct,ht_offset,ht_partner_pos);
  806.       // Also: Die Eintraege kommen von ht_entry.page_list_offset 
  807.       //       nach ht_partner_entry.page_list_offset
  808.  
  809.       // Gehe die alte Seitenliste durch und schiebe jeden Seiteneintrag,
  810.       // dessen Hashwert ein anderes nec_local_depth.tes Bit aufweist
  811.       // als in org_hash_value, auf die neue Seitenliste
  812.  
  813.    sos_Offset old_page_offset  = page_list_offset;
  814.    sos_Offset read_page_offset = old_page_offset;
  815.    sos_Offset new_page_offset  = ht_partner_entry.page_list_offset;
  816.    sos_Int bit                 = LSHIFT(1,nec_local_depth-1);
  817.    sos_Int should_be_bit       = org_hash_value BITAND bit;
  818.  
  819.    page_t old_page;
  820.    page_header_t old_page_header = read_page_header(ct,old_page_offset);
  821.    old_page.page_header =    old_page_header;
  822.    sos_Int old_entry_no     = 0;
  823.    sos_Int old_page_no      = 1;
  824.    sos_Bool add_old_page    = FALSE;
  825.  
  826.    page_t new_page;
  827.    sos_Int new_entry_no     = 0;
  828.    sos_Int new_page_no      = 1;
  829.  
  830.    page_header_t new_page_header = read_page_header(ct,new_page_offset);
  831.    new_page.page_header = new_page_header;
  832.  
  833.    page_t r_page;
  834.    page_header_t r_page_header = read_page_header(ct,read_page_offset);
  835.  
  836.    sos_Int no_of_pages = sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages();
  837.    for (sos_Int read_page_no=1;
  838.         read_page_no <= r_page_header.pages;
  839.         read_page_no++)
  840.    {  sos_Int read_entries = (r_page_header.pages > read_page_no)?
  841.                           max_page_entries:r_page_header.entries_on_last_page;
  842.       read_page(list_cursor, ct,read_page_offset, read_entries, r_page);
  843.       read_page_offset = r_page.page_header.next_page;
  844.  
  845.          // Gehe die alte Seite durch und kopiere die passenden Eintraege
  846.          // auf die neue Seite. 
  847.       for (sos_Int read_no=0;read_no<read_entries;read_no++) 
  848.       {  if ((r_page.entry[read_no].hash_value BITAND bit) !=should_be_bit)
  849.             {     // gesetztes  Bit => Eintrag auf neue Seite
  850.  
  851.                   // Ist neue Seite schon vollstaendig beschrieben ?
  852.                if (new_entry_no == max_page_entries)
  853.                {     // Falls die neue Seite bereits voll ist, erweitere Liste
  854.                   sos_Offset last_page = 
  855.                      increase_page_list(list_cursor, ct, 
  856.                                         ht_partner_entry.page_list_offset,
  857.                                         new_page_header, new_page_offset);
  858.  
  859.                   no_of_pages++;
  860.                   new_page.page_header = new_page_header;
  861.                   new_page.page_header.next_page = last_page;
  862.  
  863.                      // und schreibe die volle Seite aus
  864.                   write_page(list_cursor, ct, new_page_offset, 
  865.                             max_page_entries, new_page);
  866.  
  867.                   new_entry_no = 0;
  868.                   new_page_offset = last_page;
  869.                   new_page_no++;
  870.  
  871.                }
  872.                new_page.entry[new_entry_no] = r_page.entry[read_no]; 
  873.                   // Falls list_cursor == FALSE schadet 
  874.                   // die folgende Zeile nichts
  875.                new_page.list[new_entry_no++] = r_page.list[read_no];
  876.             }
  877.          else
  878.             {     // Ist die alte Seite schon vollstaendig beschrieben ?
  879.                if (old_entry_no == max_page_entries)
  880.                {     // Ja, schreibe alte volle Seite aus
  881.                   write_page(list_cursor, ct,
  882.                              old_page_offset, max_page_entries, old_page);
  883.  
  884.                   old_page_no++;
  885.                   old_page_offset = old_page.page_header.next_page;
  886.  
  887.                      // Lese den Vorwaertsverweis der naechsten Seite
  888.                   if (old_page_no < old_page_header.pages)
  889.                     old_page.page_header=read_page_header(ct,old_page_offset);
  890.  
  891.                   old_entry_no = 0;
  892.                }
  893.                old_page.entry[old_entry_no] = r_page.entry[read_no];
  894.                   // Falls list_cursor == FALSE schadet 
  895.                   // die folgende Zeile nichts
  896.                old_page.list[old_entry_no++] = r_page.list[read_no];
  897.             }
  898.       } 
  899.    } 
  900.                   
  901.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(no_of_pages);
  902.  
  903.       // Falls eine neue Seite noch nicht ausgeschrieben ist, tue dies
  904.    if (new_entry_no > 0)
  905.    {  new_page.page_header.entries_on_last_page = new_entry_no;
  906.       new_page.page_header.pages = new_page_no;
  907.       write_page(list_cursor, ct,new_page_offset, new_entry_no, new_page);
  908.    }
  909.  
  910.       // Korrigiere Seitenheader der ersten neuen Seite
  911.    new_page_header.entries_on_last_page = new_entry_no;
  912.    new_page_header.pages = new_page_no;
  913.  
  914.       // Schreibe evt. den Seitenheader
  915.    if ((new_page_header.pages > 1) OR (new_entry_no == 0))
  916.       write_page_header(ct,ht_partner_entry.page_list_offset,new_page_header);
  917.  
  918.  
  919.       // Falls eine alte Seite noch nicht ausgeschrieben wurde, tue dies
  920.    if (old_entry_no > 0)
  921.    {  old_page.page_header.entries_on_last_page = old_entry_no;
  922.       old_page.page_header.pages = old_page_no;
  923.       write_page(list_cursor, ct,old_page_offset, old_entry_no, old_page);
  924.    }
  925.  
  926.       // Falls die alte Seitenliste eine volle Liste ist, lasse eine
  927.       // leere Seite dranhaengen, da auf der alten Seitenliste ein
  928.       // neuer Eintrag erfolgen soll.
  929.    if (old_entry_no == max_page_entries)
  930.    {  old_entry_no = 0;
  931.       old_page_no++;
  932.       add_old_page = TRUE;
  933.    }
  934.  
  935.       // Korrigiere Seitenheader der ersten alten Seite
  936.    old_page_header.entries_on_last_page = old_entry_no;
  937.    old_page_header.pages = old_page_no;
  938.  
  939.       // Schreibe evt. alten Seitenheader
  940.    if ((old_page_header.pages > 1) OR (old_entry_no == 0))
  941.       write_page_header(ct,page_list_offset, old_page_header);
  942.  
  943.       // Gebe den Rest der alten Seitenliste frei
  944.    if (old_page_no < r_page_header.pages) 
  945.    {  destroy_page_list(list_cursor, ct, old_page.page_header.next_page, 
  946.                         r_page_header.pages-old_page_no);
  947.       sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(no_of_pages - (r_page_header.pages - old_page_no));
  948.    }
  949.    TT(agg_M, T_LEAVE);
  950. } // ** Mapping::split_page **
  951.  
  952.  
  953. // ************************************************************************** 
  954. void _sos_Object_sos_Object_Mapping::increase_hash_table(sos_Typed_id &_tpid)
  955. // ************************************************************************** 
  956. // erweitere die gesamte Hash-Tabelle, d.h. allokiere
  957. // doppelt soviel Platz wie jetzt belegt wird, kopiere
  958. // die alte Hash-Tabelle in die erste Haelfte und danach
  959. // in die zweite Haelfte. => Auf jede Seite
  960. // existieren zwei Verweise. Wirf die alte Hashtabelle weg
  961. {  T_PROC("Mapping::increase_hash_table");
  962.    TT(agg_M, T_ENTER);
  963.    sos_Container ct = sos_Object_sos_Object_Mapping::make(_tpid,this).container(); 
  964.    sos_Int old_ht_entries = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  965.    sos_Int old_ht_size = old_ht_entries*HT_ENTRY_SIZE;
  966.    sos_Offset new_ht_offset = ct.allocate(old_ht_size*2);
  967.  
  968.       // kopiere bisherige Hashtabelle zweimal 
  969.       // hintereinander in den neu allokierten Platz
  970.    ct.copy(sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(), old_ht_size, ct, new_ht_offset);
  971.    ct.copy(sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(), old_ht_size, ct, new_ht_offset+old_ht_size);
  972.  
  973.       // Wirf alte Hash-tabelle weg
  974.    ct.deallocate(sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(), old_ht_size);
  975.  
  976.       // markiere die Neue
  977.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_ht_offset(new_ht_offset);
  978.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_ht_entries(old_ht_entries * 2);
  979.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_global_depth(sos_Object_sos_Object_Mapping::make(_tpid,this).get_global_depth() + 1);
  980.    TT(agg_M, T_LEAVE);
  981. } // ** Mapping::increase_hash_table **
  982.  
  983. // increase_ht_structur__F8sos_Booliiiiii
  984. // ************************************************************************** 
  985. sos_Bool increase_ht_structur(sos_Bool list_cursor,
  986.                               sos_Int global_depth, 
  987.                               sos_Int ht_entries,
  988.                               sos_Int no_of_pages,
  989.                               sos_Int length,
  990.                               sos_Int local_depth, 
  991.                               sos_Int nec_local_depth)
  992. // ************************************************************************** 
  993. // entscheidet, ob wegen eines Seitenueberlaufs die HT-Struktur
  994. // vergoessert werden soll, oder an die Seitenliste eine Seite
  995. // angehaengt wird.
  996. {  
  997.    T_PROC("increase_ht_structur");
  998.    TT(agg_M, T_ENTER);
  999.  
  1000.       // Falls die HT nicht vergroessert werden muesste, sondern 
  1001.       // eine Seitenteilung reichen wuerde, plaediere immer fuer die
  1002.       // Erweiterung der HT
  1003.    if (global_depth >= nec_local_depth)
  1004.    {  TT(agg_M, T_LEAVE)
  1005.       return TRUE;
  1006.    }
  1007.  
  1008.       // Berechne den Platzbedarf bei Vergroesserung der HT-Struktur
  1009.    sos_Int page_size = PAGE_SIZE(list_cursor);
  1010.    sos_Int ht_memory; // Bei HT-Erweiterung
  1011.    sos_Int pl_memory; // Bei Seitenlisten Erweiterung
  1012.    
  1013.       // Bei normaler  Speicherausnutzung, d.h. Jede Seite ist 
  1014.       // zur Haelfte gefuellt, gibt die Kennzahl 100, sonst > 100
  1015.       // Ist die Ausnutzung besser, gilt Kennzahl < 100
  1016.  
  1017.       // Bedarf der jetzigen Hashtabelle
  1018.    sos_Int ht_use = ht_entries*HT_ENTRY_SIZE;
  1019.   
  1020.       // Bedarf der jetzigen saemtlichen Seiten
  1021.    sos_Int page_lists_use = no_of_pages*page_size;
  1022.  
  1023.       // Berechne den Speicher, der beim Erweitern der HT-Struktur
  1024.       // zusaetzlich benoetigt wird
  1025.  
  1026.       // Fuer jedes Splitten kommt eine Seite dazu
  1027.    sos_Int increasing_use = (nec_local_depth-local_depth)*page_size;
  1028.       // Fuer das Erweitern der HT kommt immer die bisherige Groesse dazu
  1029.    increasing_use += (LSHIFT(1,nec_local_depth) - LSHIFT(1,global_depth))
  1030.                      *HT_ENTRY_SIZE;
  1031.  
  1032.    sos_Int ht_memory_used = ht_use + page_lists_use + increasing_use;
  1033.       // Bei der Alternative der Seitenliste kommt nur eine Seite dazu;
  1034.    sos_Int pl_memory_used = ht_use + page_lists_use + page_size;
  1035.  
  1036.       // Berechne den optimalen Platzbedarf. Er ergibt sich durch 
  1037.       // zu drei/viertel gefuellte Seiten, wobei jeder Verweis auf genau
  1038.       // eine Seite zeigt.=> Berechne Anzahl der noetigen Seiten = Verweise,
  1039.       // plumitiziere mit Platzbedarf
  1040.    sos_Int opt_entries = MAX_PAGE_ENTRIES(list_cursor)*3/4;
  1041.    sos_Int opt_memory_used = (page_size + HT_ENTRY_SIZE)*
  1042.                          length/opt_entries;
  1043.  
  1044.    ht_memory = (ht_memory_used*100) / opt_memory_used;
  1045.    pl_memory = (pl_memory_used*100) / opt_memory_used;
  1046.   
  1047.  
  1048.       // Berechne die Kennzahl der Zeiteffizienz 
  1049.       // Es wird die durchschnittliche Laenge einer Seitenliste berechnet
  1050.       // Falls keine Seitenlisten existieren, so ist die Effizienz
  1051.       // optimal. Die HT-Erweiterung ist in diesem Sinne optimal, auch wenn 
  1052.       // durch fruehere Seitenlisten die Effizienz nicht 1000 entspricht, 
  1053.       // ist der einzige moegliche Weg dorthin die HT-Erweiterung.
  1054.  
  1055.    sos_Int ht_eff = 100;
  1056.    sos_Int pl_eff = 100*(no_of_pages+1)/ht_entries;
  1057.  
  1058.  
  1059.       // Jetzt kommt die Entscheidung: Beide Kennzahlen
  1060.       // werden gleich gewichtet und verglichen
  1061.    sos_Bool result = FALSE;
  1062.    if ((ht_memory + ht_eff) <= (pl_memory + pl_eff))
  1063.       result = TRUE;
  1064.  
  1065.    TT(agg_M, T_LEAVE);
  1066.    return result;
  1067. } // ** Mapping::increase_ht_structur **
  1068.  
  1069.  
  1070. // ************************************************************************** 
  1071. sos_Int neccessary_local_depth(sos_Bool      list_cursor,
  1072.                                sos_Container ct, 
  1073.                                sos_Bool      key_based_on_equal,
  1074.                                sos_Offset    page_list_offset, 
  1075.                                sos_Char      local_depth,
  1076.                                sos_Offset&   last_page_offset,
  1077.                                sos_Int       org_hash_value, 
  1078.                                sos_Object    key)
  1079. // ************************************************************************** 
  1080. // Es wird berechnet, welche lokale Tiefe eine volle Seitenliste
  1081. // plus dem einzufuegenden Objekt haben muesste, damit mindestens 
  1082. // ein Seiten Eintrag abgespalten
  1083. // werden koennte. Oder: Es wird berechnet, bis zu welchem
  1084. // Bit im Hash-Wert nicht mehr alle Seiteneintraege gleich sind
  1085. // Wird dagegen ein Eintrag gefunden, der durch den neuen Eintrag
  1086. // ersetzt wuerde, so wird dieselbe lokale Tiefe zurueckgeliefert
  1087. {  T_PROC("neccessary_local_depth");
  1088.    TT(agg_M, T_ENTER);
  1089.  
  1090.    sos_Int hash_value = org_hash_value;
  1091.    sos_Int nec_local_depth = MAX_GLOBAL_DEPTH;
  1092.    sos_Offset page_offset = page_list_offset;
  1093.  
  1094.    page_header_t first_page_header;
  1095.    first_page_header = read_page_header(ct, page_list_offset);
  1096.    sos_Int pages = first_page_header.pages;
  1097.    sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
  1098.    sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  1099.       // Durchlaufe alle Seiten
  1100.    for (sos_Int page_no=1; 
  1101.         (page_no<=pages);
  1102.         page_no++)
  1103.    {     // Diese Schleife darf nicht vorher abgebrochen werden, da
  1104.          // last_page_offset als Ausgabeparameter erwartet wird
  1105.  
  1106.       page_t page;
  1107.       if (page_no == pages) 
  1108.      entries_on_page = entries_on_last_page;
  1109.       read_page(list_cursor, ct, page_offset,entries_on_page, page);
  1110.  
  1111.       last_page_offset = page_offset;
  1112.       page_offset = page.page_header.next_page;
  1113.  
  1114.          // Durchlaufe alle Eintraege auf dieser Seite
  1115.       for (sos_Int entry_no = 0;
  1116.            (entry_no < entries_on_page);
  1117.            entry_no++)
  1118.       {  sos_Int tmp_hash_value = page.entry[entry_no].hash_value;
  1119.  
  1120.          if (org_hash_value == tmp_hash_value)
  1121.          {  sos_Object o = make_Object(page.entry[entry_no].key);
  1122.             if (agg_same_entity (key, o,key_based_on_equal, EQ_STRONG))
  1123.             {     // das Objekt wuerde dieses Objekt ersetzen, also
  1124.                // keine Erhoehung der lokalen Tiefe notwendig
  1125.            TT(agg_M, T_LEAVE);
  1126.                return local_depth;
  1127.             }
  1128.          }
  1129.             // Ab dem wievielten Bit unterscheiden sich der bisherige 
  1130.             // Hashwert und der aktuelle Eintrag ?
  1131.          sos_Int diff_hash_value = hash_value BITXOR tmp_hash_value;
  1132.  
  1133.             // Die Bits der lokalen Tiefe sind auf alle Faelle gleich,
  1134.             // also rechne erst ab local_depth+1; 
  1135.          for (sos_Int i = local_depth+1; 
  1136.               i<=nec_local_depth; 
  1137.               i++)
  1138.             if ((RSHIFT(diff_hash_value, i-1) BITAND 1) == 1)
  1139.                nec_local_depth = i++;
  1140.       } 
  1141.    } 
  1142.  
  1143.    TT(agg_M, T_LEAVE);
  1144.    return nec_local_depth;
  1145. } // ** Mapping::neccessary_local_depth *
  1146.  
  1147. // insert_in_list__30_sos_Object_sos_Object_MappingR12sos_Typed_idG10sos_ObjectN32
  1148. // ************************************************************************** 
  1149. void _sos_Object_sos_Object_Mapping::insert_in_list
  1150.                                        (sos_Typed_id &_tpid,sos_Object key, sos_Object info, 
  1151.                                         sos_Object pred, sos_Object succ)
  1152. // ************************************************************************** 
  1153. // fuegt einen Eintrag ein und setzt ihn, falls list_cursor == TRUE
  1154. // in die durch pred und succ gegebenene Reihenfolge
  1155. {  T_PROC("Mapping::insert_in_list");
  1156.    TT(agg_M, T_ENTER);
  1157.  
  1158.       // Ist das Mapping leer, so existiert noch keine Hashtabelle
  1159.    if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries() == 0)
  1160.       sos_Object_sos_Object_Mapping::make(_tpid,this).init_table();
  1161.  
  1162.    sos_Container ct            = sos_Object_sos_Object_Mapping::make(_tpid,this).container();
  1163.    sos_Bool key_based_on_equal = sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal();
  1164.    sos_Bool list_cursor        = sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor();
  1165.    sos_Int org_hash_value      = absolute((key_based_on_equal)?
  1166.                                           key.hash_value():hash_id(key));
  1167.    sos_Int ht_pos              = org_hash_value MOD sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  1168.    sos_Offset ht_offset        = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset();
  1169.    ht_entry_t ht_entry         = read_ht_entry(ct,ht_offset,ht_pos);
  1170.  
  1171.    page_header_t page_header   = read_page_header(ct,ht_entry.page_list_offset);
  1172.  
  1173.       // Ist die Seitenliste aufgefuellt ?
  1174.    if (page_header.entries_on_last_page < MAX_PAGE_ENTRIES(list_cursor))
  1175.          // Nein, es ist noch Platz
  1176.       sos_Object_sos_Object_Mapping::make(_tpid,this).insert_in_page_list(ct, key_based_on_equal, list_cursor,
  1177.                                 ht_entry.page_list_offset, org_hash_value, 
  1178.                                 key, info, pred, succ);
  1179.    else
  1180.    {     // Die Seitenliste ist voll. Entweder wird die HT erweitert,
  1181.          // oder die Seitenliste wird um eine Seite vergroessert.
  1182.       sos_Offset last_page =0;
  1183.       sos_Int nec_local_depth = 
  1184.           neccessary_local_depth( list_cursor, ct, key_based_on_equal, 
  1185.                                   ht_entry.page_list_offset, 
  1186.                                   ht_entry.local_depth,
  1187.                                   last_page, org_hash_value, key);
  1188.  
  1189.          // Falls der Eintrag einen anderen ersetzt, so 
  1190.          // ist keine Erweiterung notwendig
  1191.       if (nec_local_depth == ht_entry.local_depth)
  1192.          sos_Object_sos_Object_Mapping::make(_tpid,this).insert_in_page_list(ct, key_based_on_equal, list_cursor,
  1193.                                    ht_entry.page_list_offset, org_hash_value, 
  1194.                                    key, info, pred, succ);
  1195.       else
  1196.       {  if (increase_ht_structur
  1197.                (list_cursor,
  1198.                 sos_Object_sos_Object_Mapping::make(_tpid,this).get_global_depth(),sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries(),
  1199.                 sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages(),sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality(),
  1200.                 ht_entry.local_depth, nec_local_depth))
  1201.          {     // Die Hash-Struktur wird vergroessert, erweitere 
  1202.            // zuerst die Hashtabelle auf die benoetigten Groesse
  1203.             for (;sos_Object_sos_Object_Mapping::make(_tpid,this).get_global_depth() < nec_local_depth;)
  1204.                sos_Object_sos_Object_Mapping::make(_tpid,this).increase_hash_table(); // veraendert get_global_depth() !
  1205.                // Teile jetzt die Seiten. Hierbei sind alle Seitenteilungen
  1206.                // ohne Objektumschaufelungen verbunden, bis auf die letzte.
  1207.                // Drum der Parameter nec_local_depth
  1208.             sos_Object_sos_Object_Mapping::make(_tpid,this).split_page (ct, list_cursor,
  1209.                              ht_entry.page_list_offset, ht_entry.local_depth, 
  1210.                              org_hash_value, nec_local_depth);
  1211.    
  1212.             ht_pos = org_hash_value MOD sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  1213.             ht_entry = read_ht_entry(ct,sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(), ht_pos);
  1214.             sos_Object_sos_Object_Mapping::make(_tpid,this).insert_in_page_list (ct, key_based_on_equal, list_cursor,
  1215.                                       ht_entry.page_list_offset, 
  1216.                                       org_hash_value, key, info, 
  1217.                                       pred, succ);
  1218.          }
  1219.          else
  1220.          {     // Die Seitenliste wird um eine Seite erweitert:
  1221.             increase_page_list(list_cursor, ct, ht_entry.page_list_offset,
  1222.                                page_header, last_page);
  1223.             sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages()+1);
  1224.  
  1225.             sos_Object_sos_Object_Mapping::make(_tpid,this).insert_in_page_list(ct, key_based_on_equal, list_cursor,
  1226.                                      ht_entry.page_list_offset,org_hash_value,
  1227.                                      key, info, pred, succ);
  1228.          }
  1229.       }
  1230.    }
  1231.    TT (agg_M,T_LEAVE);
  1232. } // ** Mapping:insert_in_list **
  1233.  
  1234. // remove_from_page_list__30_sos_Object_sos_Object_MappingR12sos_Typed_idG13sos_Container8sos_BoolT3UiiG10sos_Object
  1235. // ************************************************************************** 
  1236. sos_Object _sos_Object_sos_Object_Mapping::remove_from_page_list
  1237.                                            (sos_Typed_id &_tpid,sos_Container ct,
  1238.                                             sos_Bool      list_cursor,
  1239.                                             sos_Bool      key_based_on_equal,
  1240.                                             sos_Offset    page_list_offset,
  1241.                                             sos_Int       org_hash_value,
  1242.                                             sos_Object    key)
  1243. // ************************************************************************** 
  1244. // Liefert sos_Bool_Object::TRUE, falls der Eintrag gefunden wurde. Der Entry
  1245. // wird nicht geliefert, da er sonst mit make_Object angefasst werden muesste, 
  1246. // was er hier nicht soll.
  1247. {  T_PROC("Mapping::remove_from_page_list");
  1248.    TT(agg_M, T_ENTER);
  1249.  
  1250.    sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  1251.       // assume that key won't be found:
  1252.    sos_Object  found = make_sos_Bool_object(FALSE); 
  1253.    page_t page;
  1254.    page_header_t page_header;
  1255.    sos_Offset page_offset = page_list_offset;
  1256.    sos_Offset prev_page_offset;
  1257.    page_header = read_page_header(ct, page_offset);
  1258.    sos_Int pages = page_header.pages;
  1259.    sos_Int entries_on_last_page = page_header.entries_on_last_page;
  1260.    sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  1261.    sos_Int page_no = 1;
  1262.    sos_Int pos = -1; // entspricht "nicht gefunden";
  1263.    for (; (page_no<=pages) AND (pos == -1); page_no++)
  1264.    {  if (page_no == pages)
  1265.      entries_on_page = entries_on_last_page;
  1266.       read_page(list_cursor, ct, page_offset, entries_on_page, page);
  1267.       pos = search_page_for_key (key_based_on_equal, page, 
  1268.                                  entries_on_page, 
  1269.                                  org_hash_value,key);
  1270.       if (pos == -1)
  1271.       {  prev_page_offset  = page_offset;
  1272.          page_offset = page.page_header.next_page;
  1273.       }
  1274.    } 
  1275.    
  1276.    page_no --;
  1277.       // Im Falle von based_on_equal == TRUE ist der key nicht unbedingt 
  1278.       // derselbe wie der tatsaechlich eingetragene Schluessel. real_key
  1279.       // ist der Eingetragene. real_key ist fuer den Test auf Identitaet
  1280.       // mit dem ersten bzw. letzten Element notwendig.(Equal ginge auch,
  1281.       // dauert aber laenger).
  1282.    sos_Object real_key;  
  1283.  
  1284.    if (pos != -1)
  1285.    {  found = make_sos_Bool_object(TRUE);
  1286.       real_key = make_Object(page.entry[pos].key);
  1287.  
  1288.       sos_Object pred,succ;
  1289.       if (list_cursor)
  1290.       {  pred = make_Object(page.list[pos].pred);
  1291.          succ = make_Object(page.list[pos].succ);
  1292.       }
  1293.       sos_Object_sos_Object_Mapping::make(_tpid,this).set_cardinality(sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality() - 1);
  1294.  
  1295.          // Der zu loeschende Eintrag ist auf der letzten Seite 
  1296.       if (page_no == page_header.pages)
  1297.       {     // fuelle die Luecke auf
  1298.          if (page_header.entries_on_last_page > 1)
  1299.          {     // und korrigiere den Seitenheader
  1300.             page.entry[pos] = page.entry[--page_header.entries_on_last_page];
  1301.             page.list[pos]  = page.list[page_header.entries_on_last_page];
  1302.                // schreibe Seiteneintrag zurueck
  1303.             write_page_entry(list_cursor, ct, page_offset, pos, page);
  1304.          }
  1305.          else
  1306.             // oder deallokiere die Seite
  1307.          {  if (page_header.pages > 1)
  1308.             {  ct.deallocate(page_offset, PAGE_SIZE(list_cursor));
  1309.                page_header.pages --;
  1310.                page_header.entries_on_last_page=MAX_PAGE_ENTRIES(list_cursor);
  1311.                sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages()-1);
  1312.             }
  1313.             else
  1314.                page_header.entries_on_last_page = 0;
  1315.         }
  1316.             // schreibe Seitenheader zurueck
  1317.          write_page_header(ct,page_list_offset, page_header);
  1318.       }
  1319.       else
  1320.       {     // Falls der Eintrag nicht auf der letzten Seite war, so nimm
  1321.             // einen Eintrag der letzten Seite und schreibe ihn in die Luecke
  1322.             // hangel dich zur letzten Seite vor
  1323.          sos_Offset last_page_offset = page.page_header.next_page;
  1324.          page_header_t tmp_page_header;
  1325.          page_no++;
  1326.          for (;page_no<page_header.pages;page_no++)
  1327.          {  tmp_page_header = read_page_header(ct, last_page_offset);
  1328.             last_page_offset = tmp_page_header.next_page;
  1329.          } 
  1330.  
  1331.             // nimm von der letzten Seite den letzten Eintrag
  1332.             // und korrigiere nur den Seitenheader
  1333.          page_t tmp_page;
  1334.          read_page_entry(list_cursor, ct,last_page_offset, 
  1335.                          --page_header.entries_on_last_page,
  1336.                          tmp_page);
  1337.  
  1338.             // und fuege ihn in die Luecke
  1339.          page.entry[pos] = tmp_page.entry[page_header.entries_on_last_page];
  1340.          page.list[pos]  = tmp_page.list[page_header.entries_on_last_page];
  1341.  
  1342.          write_page(list_cursor, ct,page_offset, pos+1, page);
  1343.  
  1344.             // Falls die letzte Seite jetzt leer ist, deallokiere
  1345.          if (page_header.entries_on_last_page == 0)
  1346.          {  ct.deallocate(last_page_offset, PAGE_SIZE(list_cursor));
  1347.             page_header.entries_on_last_page = MAX_PAGE_ENTRIES(list_cursor);
  1348.             page_header.pages--;
  1349.             sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages()-1);
  1350.          }
  1351.  
  1352.             // Schreibe den Seitenheader der ersten Seite zurueck
  1353.          write_page_header(ct,page_list_offset, page_header);
  1354.       }
  1355.      
  1356.       if (list_cursor)
  1357.       {     // fuege Objekt aus der Liste
  1358.          sos_Object_sos_Object_Mapping::make(_tpid,this).write_succ_pred
  1359.             (ct, key_based_on_equal, list_cursor, pred, TRUE, succ);
  1360.          sos_Object_sos_Object_Mapping::make(_tpid,this).write_succ_pred
  1361.             (ct, key_based_on_equal, list_cursor, succ, FALSE, pred);
  1362.       
  1363.          if (real_key == sos_Object_sos_Object_Mapping::make(_tpid,this).get_last_object())
  1364.             sos_Object_sos_Object_Mapping::make(_tpid,this).set_last_object(pred);
  1365.          if (real_key == sos_Object_sos_Object_Mapping::make(_tpid,this).get_first_object())
  1366.             sos_Object_sos_Object_Mapping::make(_tpid,this).set_first_object(succ);
  1367.             
  1368.             // Letztes Objekt:
  1369.          if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality() == 0)
  1370.          {  sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  1371.             sos_Object_sos_Object_Mapping::make(_tpid,this).set_first_object(my_no_object);
  1372.             sos_Object_sos_Object_Mapping::make(_tpid,this).set_last_object(my_no_object);
  1373.          }
  1374.       }
  1375.    } 
  1376.  
  1377.    TT(agg_M, T_LEAVE);
  1378.    return found;
  1379. } // ** Mapping::remove_from_page_list **
  1380.  
  1381.  
  1382.  
  1383. // ************************************************************************** 
  1384. sos_Bool _sos_Object_sos_Object_Mapping::assemble_page(
  1385.                                            sos_Typed_id &_tpid,sos_Offset page_list_offset,
  1386.                                            sos_Char   local_depth,
  1387.                                            sos_Int    org_hash_value)
  1388. // ************************************************************************** 
  1389. {  T_PROC("Mapping::assemble_page");
  1390.    TT(agg_M, T_ENTER);
  1391.  
  1392.    sos_Container ct         = sos_Object_sos_Object_Mapping::make(_tpid,this).container(); 
  1393.    sos_Bool list_cursor     = sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor();
  1394.    sos_Int max_page_entries = MAX_PAGE_ENTRIES(list_cursor);
  1395.  
  1396.    page_t page;
  1397.    page_t partner_page;
  1398.    ht_entry_t ht_partner_entry;
  1399.  
  1400.    page.page_header     = read_page_header(ct, page_list_offset);
  1401.    sos_Int ht_partner_pos;
  1402.  
  1403.    sos_Bool assemble_flag;
  1404.       // liefere zurueck, ob verschmolzen wurde
  1405.    sos_Bool result             = FALSE; 
  1406.    sos_Bool act_page_is_read   = FALSE;
  1407.  
  1408.    do // while (assemble_flag)
  1409.    {  assemble_flag = FALSE;
  1410.  
  1411.          // zuerst eine Grob-Pruefung, ob eine Chance auf 
  1412.          // Verschmelzung besteht:
  1413.          // Ist die Seitenliste nur eine Seite, und ist sie nur 3/4 voll,
  1414.          // und gibt es ueberhaupt eine Partnerseite ?
  1415.       if ((page.page_header.entries_on_last_page <= max_page_entries*3/4) AND
  1416.           (page.page_header.pages == 1) AND
  1417.           (local_depth > 0))
  1418.       {     // Berechne die Position der Partnerseite
  1419.          ht_partner_pos     = (org_hash_value BITAND LSHIFT(1,local_depth)-1)
  1420.                               BITXOR LSHIFT(1,local_depth-1);
  1421.  
  1422.             // Lese den HT-Eintrag der Partnerseite
  1423.          ht_partner_entry =
  1424.             read_ht_entry(ct,sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),ht_partner_pos);
  1425.          
  1426.             // Hat die Partnerseite die gleiche lokale Tiefe ?
  1427.          if (ht_partner_entry.local_depth == local_depth)
  1428.          {     // Ja
  1429.                // Lese Seitenkopf der Partner Seite
  1430.             partner_page.page_header = 
  1431.                    read_page_header(ct, ht_partner_entry.page_list_offset);
  1432.             
  1433.                // Besteht die Partnerseite auch nur aus einer Seite ?
  1434.             if (partner_page.page_header.pages == 1)
  1435.             {  // passen alle Eintraege gut auf eine Seite ? (gut = 25% frei)
  1436.                assemble_flag = FALSE;
  1437.                if ((partner_page.page_header.entries_on_last_page+
  1438.                      page.page_header.entries_on_last_page)
  1439.                      <= max_page_entries*3/4)
  1440.                   assemble_flag = TRUE;
  1441.             }
  1442.          } 
  1443.       }
  1444.  
  1445.       if (assemble_flag) 
  1446.       {  result = TRUE;
  1447.  
  1448.          sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_page_lists(sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_page_lists() - 1);
  1449.  
  1450.          if (NOT (act_page_is_read))
  1451.          {  read_page(list_cursor, ct,page_list_offset, 
  1452.                       page.page_header.entries_on_last_page, page);
  1453.             act_page_is_read = TRUE;
  1454.          }
  1455.  
  1456.             // Lese Partner-Seite
  1457.          read_page(list_cursor, ct,ht_partner_entry.page_list_offset, 
  1458.                    partner_page.page_header.entries_on_last_page, 
  1459.                    partner_page);
  1460.  
  1461.             // Kopiere die Eintraege der Partnerseite 
  1462.             // auf die urspruengliche Seite
  1463.          for (sos_Int i=0; i<partner_page.page_header.entries_on_last_page;i++)
  1464.          {  page.entry[page.page_header.entries_on_last_page] = 
  1465.                partner_page.entry[i];
  1466.             page.list[page.page_header.entries_on_last_page++] = 
  1467.                partner_page.list[i];
  1468.          } 
  1469.  
  1470.             // Korrigiere die Angabe, wieviel Seiten mit einer 
  1471.             // bestimmten lokalen Tiefe existieren
  1472.          sos_Int no_of_pages_offset = sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages_offset();
  1473.          add_no_of_pages(ct,no_of_pages_offset,local_depth,-2);
  1474.          add_no_of_pages(ct,no_of_pages_offset,local_depth-1,1);
  1475.  
  1476.             // Gib die Partnerseite frei
  1477.          ct.deallocate (ht_partner_entry.page_list_offset, 
  1478.                         PAGE_SIZE(list_cursor));
  1479.          sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages()-1);
  1480.  
  1481.          write_page(list_cursor, ct,page_list_offset, 
  1482.                     page.page_header.entries_on_last_page, page);
  1483.        
  1484.          sos_Int old_local_depth = local_depth --;
  1485.  
  1486.             // Die Hashtabelle muss korrigiert werden: Alle
  1487.             // Verweise auf die Partnerseite muessen auf die verschmolzene
  1488.             // Seite umgebogen werden
  1489.             // Wie lautet der der vereinigten Seite zugeordnete Hashwertteil ? 
  1490.          sos_Int hash_value_part = ht_partner_pos BITAND 
  1491.                                (LSHIFT(1,local_depth)-1);
  1492.  
  1493.             // Laufe alle Indexe durch, die auf die neue
  1494.             // vereinigte Seite zeigen. Diese Verweise werden
  1495.             // umgebogen
  1496.          sos_Int global_depth = sos_Object_sos_Object_Mapping::make(_tpid,this).get_global_depth();
  1497.          sos_Offset ht_offset = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset();
  1498.          for (sos_Int k = 0;k<LSHIFT(1,global_depth-local_depth); k++)
  1499.          {     // verschiebe Laufindex k an richtige Position 
  1500.                // vor dem Wert der Seite
  1501.             sos_Int j = LSHIFT(k,local_depth);
  1502.                // addiere hash-Teil der Seite dazu
  1503.             j = j BITOR hash_value_part;
  1504.             
  1505.                // Dieser Eintrag muss auf die neue Seite umgebogen werden
  1506.                // d.h. vielleicht zeigt er schon auf die Seite, aber
  1507.                // die lokale Tiefe ist in jedem Fall zu hoch
  1508.             ht_entry_t ht_entry;
  1509.             ht_entry.page_list_offset = page_list_offset;
  1510.             ht_entry.local_depth = local_depth;
  1511.             write_ht_entry(ct,ht_offset,j, ht_entry);
  1512.          }
  1513.       }
  1514.    } 
  1515.    while (assemble_flag);
  1516.  
  1517.    TT(agg_M,T_LEAVE);
  1518.    return result;
  1519. } // ** Mapping::assemble_page **
  1520.  
  1521.  
  1522. // ************************************************************************** 
  1523. void _sos_Object_sos_Object_Mapping::decrease_hash_table(sos_Typed_id &_tpid)
  1524. // ************************************************************************** 
  1525. // die Hash-tabelle kann genau dann halbiert werden, wenn
  1526. // keine Seiten existieren, die nur einen Verweis in der 
  1527. // Hash-Tabelle besitzen
  1528. {  
  1529.    T_PROC("Mapping::decrease_hash_table");
  1530.    TT(agg_M, T_ENTER);
  1531.  
  1532.    sos_Container ct              = sos_Object_sos_Object_Mapping::make(_tpid,this).container(); 
  1533.    sos_Int global_depth          = sos_Object_sos_Object_Mapping::make(_tpid,this).get_global_depth();
  1534.    sos_Offset no_of_pages_offset = sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages_offset();
  1535.  
  1536.    for (;no_single_referenced_pages(ct,no_of_pages_offset,global_depth);)
  1537.    {     // Merke alte Tabellen-Position und Laenge
  1538.       sos_Int old_ht_entries   = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  1539.       sos_Int old_ht_size      = old_ht_entries*HT_ENTRY_SIZE;
  1540.       sos_Offset old_ht_offset = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset();
  1541.  
  1542.          // definiere neue Tabellen Position und Laenge
  1543.       sos_Int new_ht_entries = old_ht_entries / 2;
  1544.       sos_Int new_ht_size   = new_ht_entries*HT_ENTRY_SIZE;
  1545.       sos_Int new_ht_offset = ct.allocate(new_ht_entries*HT_ENTRY_SIZE);
  1546.       sos_Object_sos_Object_Mapping::make(_tpid,this).set_ht_entries(new_ht_entries);
  1547.       sos_Object_sos_Object_Mapping::make(_tpid,this).set_ht_offset(new_ht_offset);
  1548.  
  1549.          // kopiere erste Haelfte der alten Tabelle in neue Tabelle
  1550.       ct.copy( old_ht_offset,new_ht_size,ct,new_ht_offset); 
  1551.       global_depth--;
  1552.       
  1553.          // Gib alte Tabelle frei
  1554.       ct.deallocate(old_ht_offset,old_ht_size);
  1555.    }
  1556.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_global_depth(global_depth);
  1557.    TT (agg_M,T_LEAVE); 
  1558. } // ** decrease_hash_table
  1559.  
  1560. // ************************************************************************** 
  1561. sos_Bool get_entry (sos_Container  ct, 
  1562.                     sos_Bool       list_cursor,
  1563.                     sos_Bool       key_based_on_equal, 
  1564.                     sos_Int        ht_entries,
  1565.                     sos_Offset     ht_offset,
  1566.                     sos_Object&    key,
  1567.             sos_Bool       return_info,
  1568.             sos_Object&    info,
  1569.                     sos_Object&    pred,
  1570.                     sos_Object&    succ)
  1571. // ************************************************************************** 
  1572. // Setzt key und - falls list_cursor == TRUE - pred und succ auf die
  1573. // key-Objekte im gegebenen Mapping. Ergebnis ist das dem key entsprechende
  1574. // info. Es gilt agg_same_entity (key-vorher, key-nachher, key_based_on_equal)
  1575. // Wird return_info== TRUE uebergeben, wird info geliefert, ansonsten nicht.
  1576. // pred und succ werden nur im Falle von list_cursor == TRUE geliefert.
  1577.     
  1578. {  T_PROC("get_entry");
  1579.    TT(agg_M,T_ENTER; TI(ht_entries); TI(ht_offset));
  1580.  
  1581.    if (ht_entries>0)
  1582.    {  sos_Int org_hash_value  = absolute((key_based_on_equal)?
  1583.                                          key.hash_value() : hash_id(key));
  1584.       sos_Int ht_pos          = org_hash_value MOD ht_entries;
  1585.       ht_entry_t ht_entry     = read_ht_entry(ct,ht_offset,ht_pos);
  1586.       page_t page;
  1587.  
  1588.       sos_Offset page_offset  = ht_entry.page_list_offset;
  1589.       sos_Int pos = -1; // entspricht "nicht gefunden"
  1590.  
  1591.       page_header_t page_header = read_page_header (ct, page_offset);
  1592.       sos_Int pages = page_header.pages;
  1593.       sos_Int entries_on_last_page = page_header.entries_on_last_page;
  1594.       sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  1595.       for (sos_Int page_no = 1; (page_no<=pages) AND (pos == -1); page_no++)
  1596.       {  if (page_no == pages)
  1597.         entries_on_page = entries_on_last_page;
  1598.          
  1599.          read_page(list_cursor, ct, page_offset, entries_on_page, page);
  1600.          pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
  1601.                                      org_hash_value, key );
  1602.          if (pos == -1)
  1603.             page_offset = page.page_header.next_page;
  1604.          else
  1605.          {  if (list_cursor)
  1606.             {  pred = make_Object(page.list[pos].pred);
  1607.                succ = make_Object(page.list[pos].succ);
  1608.            sos_Bool test1 = (succ == NO_OBJECT);
  1609.            sos_Bool test2 = (pred == NO_OBJECT);
  1610.             }
  1611.             key = make_Object(page.entry[pos].key);
  1612.             if (return_info)
  1613.            info = make_Object(page.entry[pos].info);
  1614.          
  1615.             TT(agg_M, T_LEAVE);
  1616.            // gefunden !
  1617.             return TRUE;
  1618.          }
  1619.       } 
  1620.    }   
  1621.    TT(agg_M,T_LEAVE);
  1622.       // nicht gefunden:
  1623.    return FALSE;
  1624. } // ** get_entry **
  1625.  
  1626. /*
  1627. Reihenfolge in der Hashtabelle:
  1628. Die Ordnung bezieht sich immer nur auf diejenigen Verweise in der Hashtabelle,
  1629. die die ersten Verweise auf eine bestimmte Seitenliste sind. Das Durchlaufen
  1630. mit einem Cursor funktioniert auf der Version mit list_cursor == FALSE so:
  1631. Die Cursor-Operatoren wurden ueberlagert, mit dem Oeffnen eines Cursors werden
  1632. die Prozeduren read_first_object und read_last_object aufgerufen, die das 
  1633. erste und letzte Objekt liefern. open_cursor setzt nun die Variablen 
  1634. first_object und last_object.  Beim Durchlaufen mit dem Cursor wird die 
  1635. Hashtabelle solange durchsucht, bis ein Verweis gefunden wird, der der Erste
  1636. auf die referenzierte Seitenliste ist. Dies ist der Fall, wenn in der Position
  1637. der Hashtabelle (ht_pos) nur die ersten (lokale_tiefe) Bit gesetzt sind. Auf 
  1638. der Seitenliste werden die Eintraege gemaess der Reihenfolge auf der Seite 
  1639. durchlaufen. Nach dem letzten Eintrag auf der Seitenliste beginnt wieder die
  1640. Suche in der Hashtabelle nach einem ersten Verweis auf die naechste 
  1641. Seitenliste.
  1642. */
  1643.  
  1644. // ************************************************************************** 
  1645. sos_Object get_pred ( sos_Container  ct,
  1646.                       sos_Bool       key_based_on_equal,
  1647.                       sos_Object     my_no_object,
  1648.                       sos_Int        ht_entries,
  1649.                       sos_Offset     ht_offset,
  1650.                       sos_Object     key)
  1651. // ************************************************************************** 
  1652. // Diese Prozedur wird nur aufgerufen, wenn get_list_cursor() == FALSE,
  1653. // d.h. die Version ohne verkettung der Eintraege ist gefragt.
  1654. // Es wird das Objekt in der eben geschilderten Reihenfolge nach key 
  1655. // geliefert.
  1656. {  sos_Int org_hash_value  =absolute((key_based_on_equal)?
  1657.                                       key.hash_value() : hash_id(key));
  1658.    sos_Int ht_pos = org_hash_value MOD ht_entries;
  1659.    sos_Object result;
  1660.  
  1661.    ht_entry_t ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1662.    page_t page;
  1663.    sos_Int first_link = FIRST_LINK(ht_pos, ht_entry.local_depth);
  1664.    ht_pos = first_link;
  1665.    sos_Offset page_offset = ht_entry.page_list_offset;
  1666.  
  1667.    page_header_t page_header = read_page_header (ct, page_offset);
  1668.    sos_Int pages = page_header.pages;
  1669.    sos_Int entries_on_last_page = page_header.entries_on_last_page;
  1670.    sos_Int entries_on_page = max_page_entries_without_list;
  1671.    result = my_no_object;
  1672.    sos_Int pos = -1; // entspricht "nicht gefunden"
  1673.    for (sos_Int page_no = 1;
  1674.         (page_no<=pages) AND (pos == -1);
  1675.         page_no++)
  1676.    {  if (page_no == pages)
  1677.      entries_on_page = entries_on_last_page;
  1678.  
  1679.       read_page(FALSE, ct, page_offset, entries_on_page, page);
  1680.       pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
  1681.                                   org_hash_value, key );
  1682.       if (pos == -1)
  1683.       {  page_offset = page.page_header.next_page;
  1684.          result = make_Object(page.entry[entries_on_page-1].key);
  1685.       }
  1686.       else
  1687.       {     // Findet sich der Vorgaenger auf derselben Seite ?
  1688.          if (pos > 0)
  1689.             result = make_Object(page.entry[pos-1].key);
  1690.          else
  1691.          {     // Falls eine vorherige Seite in der seitenliste
  1692.                // existiert, so wurde ihr letzter Eintrag in
  1693.                // result bereits gesetzt. Ist es jedoch die erste Seite
  1694.                // muss auf eine vorherige Seitenliste gegangen werden
  1695.             if (page_no == 1)
  1696.             {  sos_Bool found = FALSE;
  1697.                do
  1698.                {  ht_pos--;
  1699.                   do
  1700.                   {  if (ht_pos >= 0)
  1701.                      {     // suche den naechsten ersten verweis ab ht_pos;
  1702.                         ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1703.                         first_link = FIRST_LINK(ht_pos, ht_entry.local_depth);
  1704.  
  1705.                         if (first_link != ht_pos)
  1706.                            ht_pos--;
  1707.                       }
  1708.                   } while ((first_link != ht_pos) AND (ht_pos >= 0));
  1709.  
  1710.                   if (ht_pos >= 0)
  1711.                   {  page_header = 
  1712.                        read_page_header(ct,ht_entry.page_list_offset);
  1713.  
  1714.                         // Falls auf dieser Seitenliste ein
  1715.                         // Eintrag ist, lese ihn, sonst bleibt found == FALSE
  1716.                      if ((page_header.pages > 1) OR
  1717.                          (page_header.entries_on_last_page > 0))
  1718.                      {  found = TRUE;
  1719.                            // lese letzte Seite
  1720.                         sos_Int i = read_page(FALSE, ct,page_header, ht_entry,
  1721.                                           page_header.pages, page);
  1722.                         result = make_Object(page.entry[i-1].key);
  1723.                      }
  1724.                   }
  1725.                } while ((NOT found) AND (ht_pos >= 0));
  1726.             }
  1727.          }
  1728.       }
  1729.    } 
  1730.  
  1731.    return result;
  1732. } // ** get_pred **
  1733.  
  1734. // ************************************************************************** 
  1735. sos_Object get_succ ( sos_Container  ct,
  1736.                       sos_Bool       key_based_on_equal,
  1737.                       sos_Object     my_no_object,
  1738.                       sos_Int        ht_entries,
  1739.                       sos_Offset     ht_offset,
  1740.                       sos_Object     key)
  1741. // ************************************************************************** 
  1742. {  sos_Int org_hash_value = absolute((key_based_on_equal)?
  1743.                                      key.hash_value() : hash_id(key));
  1744.    sos_Int ht_pos = org_hash_value MOD ht_entries;
  1745.    sos_Object result;
  1746.  
  1747.    ht_entry_t ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1748.    page_t page;
  1749.    sos_Int first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
  1750.    ht_pos = first_link;
  1751.    sos_Offset page_offset = ht_entry.page_list_offset;
  1752.  
  1753.    page_header_t page_header = read_page_header (ct, page_offset);
  1754.    sos_Int pages = page_header.pages;
  1755.    sos_Int entries_on_last_page = page_header.entries_on_last_page;
  1756.    sos_Int entries_on_page = max_page_entries_without_list;
  1757.    result = my_no_object;
  1758.    sos_Int pos = -1; // entspricht "nicht gefunden"
  1759.    for (sos_Int page_no = 1; (page_no<=pages) AND (pos == -1); page_no++)
  1760.    {  if (page_no == pages)
  1761.      entries_on_page = entries_on_last_page;
  1762.  
  1763.       read_page(FALSE, ct, page_offset, entries_on_page, page);
  1764.       pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
  1765.                                   org_hash_value, key );
  1766.       if (pos == -1)
  1767.          page_offset = page.page_header.next_page;
  1768.       else
  1769.       {     // Findet sich der Nachfolger auf derselben Seite ?
  1770.          if (pos < entries_on_page-1)
  1771.             result = make_Object(page.entry[pos+1].key);
  1772.          else
  1773.          {  if (page_no < page_header.pages)
  1774.             {  read_page(FALSE, ct, page.page_header.next_page, 1, page);
  1775.                result = make_Object(page.entry[0].key);
  1776.             }
  1777.             else
  1778.             {     // Der Schluessel ist der letzte Eintrag auf der 
  1779.                   // Seitenliste, der Nachfolger ist auf der 
  1780.                   // naechsten Seitenliste
  1781.                sos_Bool found = FALSE;
  1782.                do
  1783.                {  ht_pos++;
  1784.                   do
  1785.                   {     // suche den naechsten ersten verweis ab ht_pos;
  1786.                         // read ht_entry
  1787.                      if (ht_pos < ht_entries)
  1788.                      {  ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1789.                         first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
  1790.                         if (first_link != ht_pos)
  1791.                            ht_pos++;
  1792.                      }
  1793.                    } while ((first_link != ht_pos) AND (ht_pos < ht_entries));
  1794.                       
  1795.                    if (ht_pos < ht_entries)
  1796.                    {     // lese den Seitenkopf und das erste 
  1797.                          // Objekt dieser Seite
  1798.                       read_page(FALSE,ct, ht_entry.page_list_offset, 1, page);
  1799.                       if ((page.page_header.pages > 1) OR
  1800.                           (page.page_header.entries_on_last_page > 0))
  1801.                       {  found = TRUE;
  1802.                          result = make_Object(page.entry[0].key);
  1803.                       }
  1804.                   }
  1805.                } while ((NOT found) AND (ht_pos < ht_entries));
  1806.             }
  1807.          }
  1808.       }
  1809.    } 
  1810.  
  1811.    return result;
  1812. } // ** Mapping::get_succ **
  1813.  
  1814.  
  1815. // ************************************************************************** 
  1816. sos_Object _sos_Object_sos_Object_Mapping::search_succ_pred
  1817.                                              (sos_Typed_id &_tpid,sos_Object key, sos_Int steps)
  1818. // ************************************************************************** 
  1819. {  T_PROC("Mapping::search_succ_pred");
  1820.    TT(agg_M, T_ENTER; TI (steps));
  1821.  
  1822.    sos_Container ct             = sos_Object_sos_Object_Mapping::make(_tpid,this).container();
  1823.    sos_Bool key_based_on_equal  = sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal();
  1824.    sos_Bool list_cursor         = sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor();
  1825.    sos_Object my_no_object      = sos_Object_sos_Object_Mapping::make(_tpid,this);
  1826.    sos_Int ht_entries           = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  1827.    sos_Offset ht_offset         = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset();
  1828.    sos_Object dummy_info;  // wird in get_entry nicht angefasst
  1829.  
  1830.    for (;steps != 0;)
  1831.    {  sos_Object pred,succ;
  1832.       if (list_cursor)
  1833.       {  get_entry(ct, list_cursor, key_based_on_equal,
  1834.                    ht_entries,ht_offset, 
  1835.                    key, FALSE, dummy_info, pred,succ);
  1836.          if (steps > 0)
  1837.          {  if (succ == my_no_object)
  1838.         {  TT(agg_M, T_LEAVE);
  1839.                return my_no_object;
  1840.             }
  1841.             key = succ;
  1842.             steps--;
  1843.          }
  1844.          else
  1845.          {  if (pred == my_no_object)
  1846.         {  TT(agg_M, T_LEAVE);
  1847.                return my_no_object;
  1848.             }
  1849.             key = pred;
  1850.             steps++;
  1851.          }
  1852.       }
  1853.       else
  1854.       {  if (steps > 0)
  1855.          {  succ = get_succ(ct,key_based_on_equal,my_no_object,
  1856.                             ht_entries,ht_offset,key);
  1857.             if (succ == my_no_object)
  1858.         {  TT(agg_M, T_LEAVE);
  1859.                return my_no_object;
  1860.             } 
  1861.             key = succ;
  1862.             steps--;
  1863.          }
  1864.          else
  1865.          {  pred = get_pred(ct,key_based_on_equal,my_no_object,
  1866.                             ht_entries,ht_offset,key);
  1867.             if (pred == my_no_object)
  1868.             {  TT(agg_M, T_LEAVE);
  1869.            return my_no_object;
  1870.             }
  1871.             key = pred;
  1872.             steps++;
  1873.          }
  1874.       } 
  1875.    }
  1876.    TT(agg_M,T_LEAVE);
  1877.    return key;
  1878. } // ** Mapping::search_succ_pred **
  1879.  
  1880.  
  1881. // ************************************************************************** 
  1882. sos_Object read_last_object(sos_Container ct,
  1883.                             sos_Offset    ht_offset,
  1884.                             sos_Int       length,
  1885.                             sos_Object    my_no_object,
  1886.                             sos_Int       ht_entries)
  1887. // ************************************************************************** 
  1888. {  sos_Int ht_pos = ht_entries-1;
  1889.    sos_Bool found = FALSE;
  1890.    if (length == 0)
  1891.        return my_no_object;
  1892.    sos_Object result;
  1893.    ht_entry_t ht_entry;
  1894.    page_t page;
  1895.    page_header_t page_header;
  1896.    sos_Int first_link;
  1897.    do
  1898.    {  do
  1899.       {     // suche den vorherigen ersten Verweis ab ht_pos rueckwaerts
  1900.          ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1901.          first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
  1902.          if (first_link != ht_pos)
  1903.              ht_pos--;
  1904.       } while (first_link != ht_pos);
  1905.  
  1906.          // lese den page_header um festzustellen, ob auf der
  1907.          // Seitenliste ein Objekt ist
  1908.       page_header = read_page_header(ct,ht_entry.page_list_offset);
  1909.       if ((page_header.pages > 1) OR
  1910.           (page_header.entries_on_last_page > 0))
  1911.       {  found = TRUE;
  1912.             // lese letzte Seite
  1913.          read_page(FALSE,ct ,page_header, ht_entry, page_header.pages, page);
  1914.          result=make_Object(page.entry[page_header.entries_on_last_page-1].key);
  1915.       }
  1916.       else
  1917.          ht_pos--;
  1918.    } while (NOT found);
  1919.  
  1920.    return result;
  1921. } // ** Mapping::read_last_object **
  1922.  
  1923. // ************************************************************************** 
  1924. sos_Object read_first_object(sos_Container ct,
  1925.                              sos_Offset    ht_offset,
  1926.                              sos_Int       length,
  1927.                              sos_Object    my_no_object)
  1928. // ************************************************************************** 
  1929. {   sos_Int ht_pos = 0;
  1930.     sos_Bool found = FALSE;
  1931.     if (length == 0)
  1932.        return my_no_object;
  1933.     sos_Object result;
  1934.     ht_entry_t ht_entry;
  1935.     page_t page;
  1936.     sos_Int first_link;
  1937.  
  1938.     do
  1939.     {  do
  1940.        {     // suche den naechsten ersten verweis ab ht_pos;
  1941.              // read ht_entry
  1942.           ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1943.           first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
  1944.           if (first_link != ht_pos)
  1945.              ht_pos++;
  1946.        }
  1947.        while (first_link != ht_pos);
  1948.         
  1949.        // lese die Seite und das erste Objekt von diesem Verweis
  1950.        read_page(FALSE, ct, ht_entry.page_list_offset, 1, page);
  1951.        if ((page.page_header.pages > 1) OR
  1952.            (page.page_header.entries_on_last_page > 0))
  1953.        {  found = TRUE;
  1954.           result = make_Object(page.entry[0].key);
  1955.        }
  1956.        else
  1957.           ht_pos++;
  1958.     } while (NOT found);
  1959.     return result;
  1960. } // ** Mapping::read_first_object **
  1961.  
  1962.  
  1963. // ************************************************************************** 
  1964. void destroy_ht (sos_Bool       list_cursor,
  1965.                  sos_Container  ct, 
  1966.                  sos_Int        ht_entries, 
  1967.                  sos_Int        global_depth,
  1968.                  sos_Offset     ht_offset)
  1969. // ************************************************************************** 
  1970. {  T_PROC("destroy_ht ");
  1971.    TT (agg_M, T_ENTER; TI(ht_entries); TI(global_depth));
  1972.       // loescht alle Eintrage und die Hashtabelle,
  1973.  
  1974.    ht_entry_t ht_entry;
  1975.  
  1976.    for (sos_Int ht_pos=0;ht_pos < ht_entries;ht_pos++)
  1977.    {  ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1978.       sos_Int local_depth = ht_entry.local_depth;
  1979.          // Berechne denjenigen Teil des Hashwertes, der auf der
  1980.          // Seitenliste unterschieden wird, dies ist gleichzeitig
  1981.          // der erste Verweis auf die Seitenliste
  1982.       sos_Int hash_value_part = FIRST_LINK(ht_pos, local_depth);
  1983.  
  1984.          // Berechne den letzten Verweis auf diese Seiteliste
  1985.       sos_Int last_link = LSHIFT(LSHIFT(1,global_depth-local_depth)-1,
  1986.                              local_depth) BITAND hash_value_part;
  1987.          // es muss der letzte Verweis sein, andernfalls wuerde die Kiste
  1988.          // beim nachfolgenden Lesen der lokalen Tiefe abschmieren,
  1989.          // da die Seite schon deallokiert waere.
  1990.  
  1991.          // Falls der gefundendene Verweis der letzte auf diese Seitenliste
  1992.          // ist, so deallokiere diese
  1993.       if (last_link == ht_pos) 
  1994.       {  page_header_t page_header = 
  1995.              read_page_header(ct,ht_entry.page_list_offset);
  1996.          destroy_page_list(list_cursor, ct,
  1997.                            ht_entry.page_list_offset, page_header.pages);
  1998.       }
  1999.    } 
  2000.  
  2001.    if (ht_entries>0)
  2002.       ct.deallocate(ht_offset,ht_entries*HT_ENTRY_SIZE);
  2003.  
  2004.    TT(agg_M,T_LEAVE);
  2005. } // ** Mapping::destroy_ht **
  2006.  
  2007. // ************************************************************************** 
  2008. void _sos_Object_sos_Object_Mapping::init_table (sos_Typed_id &_tpid)
  2009. // ************************************************************************** 
  2010. {  T_PROC("Mapping::init_table");
  2011.    TT(agg_H, T_ENTER);
  2012.  
  2013.       // create a hash-tab
  2014.       // Ein Eintrag besteht aus einem Offset
  2015.       // also einem Zeiger auf eine Seite
  2016.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_ht_entries(1);
  2017.    sos_Container ct  = sos_Object_sos_Object_Mapping::make(_tpid,this).container();
  2018.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_ht_offset(ct.allocate (sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries()*HT_ENTRY_SIZE)); 
  2019.  
  2020.       // no_of_pages[i] gibt an, wieviel Seiten mit der lokalen
  2021.       // Tiefe i existieren 
  2022.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages_offset(ct.allocate(NO_OF_PAGES_ARRAY_SIZE));
  2023.    sos_Char mem [NO_OF_PAGES_ARRAY_SIZE];
  2024.    for (sos_Int i = 0;i< NO_OF_PAGES_ARRAY_SIZE;i++) mem[i] = 0;
  2025.    ct.write(sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages_offset(), NO_OF_PAGES_ARRAY_SIZE, &mem);
  2026.  
  2027.    ht_entry_t ht_entry;
  2028.    ht_entry.page_list_offset = ct.allocate(PAGE_SIZE(sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor()));
  2029.    ht_entry.local_depth = 0;
  2030.    write_ht_entry(ct, sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),0,ht_entry);
  2031.  
  2032.    page_header_t page_header;
  2033.    page_header.pages = 1;
  2034.    page_header.entries_on_last_page = 0;
  2035.    write_page_header(ct,ht_entry.page_list_offset,page_header);
  2036.  
  2037.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(1);
  2038.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_page_lists(1);
  2039.    add_no_of_pages(ct,sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages_offset(),0,1);
  2040.  
  2041.    TT(agg_H,T_LEAVE);
  2042. } // ** Mapping::init_table **
  2043.  
  2044. // ************************************************************************** 
  2045. void _sos_Object_sos_Object_Mapping::local_initialize
  2046.                                        (sos_Object_sos_Object_Mapping map)
  2047. // ************************************************************************** 
  2048. {  T_PROC("Mapping::local_initialize");
  2049.    TT(agg_H, T_ENTER);
  2050.  
  2051.    sos_Object my_no_object = map;
  2052.  
  2053.    map.set_cardinality (0);
  2054.    map.set_first_object(my_no_object); 
  2055.    map.set_last_object(my_no_object);
  2056.    map.set_ht_entries(0);
  2057.    map.set_global_depth(0);
  2058.    map.set_no_of_pages_offset(NIL);
  2059.    map.set_no_of_pages(0);
  2060.    map.set_ht_offset(NIL);
  2061.  
  2062.    TT(agg_H,T_LEAVE);
  2063. }; // ** Mapping::local_initialize **
  2064.  
  2065. // ************************************************************************** 
  2066. void _sos_Object_sos_Object_Mapping::local_finalize
  2067.                                        (sos_Object_sos_Object_Mapping map)
  2068. // ************************************************************************** 
  2069. {  T_PROC("Mapping::local_finalize");
  2070.    TT (agg_H, T_ENTER);
  2071.  
  2072.    destroy_ht(map.get_list_cursor(), map.container(), map.get_ht_entries(), 
  2073.               map.get_global_depth(), map.get_ht_offset());
  2074.  
  2075.    TT (agg_H, T_LEAVE);
  2076. } // ** Mapping::local_finalize **
  2077.  
  2078. // ************************************************************************** 
  2079. sos_Bool _sos_Object_sos_Object_Mapping::is_key (sos_Typed_id &_tpid,sos_Object key)
  2080. // ************************************************************************** 
  2081. {  T_PROC("Mapping::is_key");
  2082.    TT(agg_H, T_ENTER);
  2083.    sos_Object dummy_pred,dummy_succ,dummy_info;
  2084.    sos_Bool result = FALSE;
  2085.    sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2086.    result = get_entry(sos_Object_sos_Object_Mapping::make(_tpid,this).container(), sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(),  
  2087.                       sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal(), 
  2088.                       sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries(), sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(), 
  2089.                       key, FALSE, dummy_info, dummy_pred,dummy_succ);
  2090.    TT(agg_H, T_LEAVE);
  2091.    return result;
  2092. } // ** Mapping::is_key **
  2093.  
  2094.  
  2095. // ************************************************************************** 
  2096. sos_Bool _sos_Object_sos_Object_Mapping::is_info (sos_Typed_id &_tpid,sos_Object info)
  2097. // ************************************************************************** 
  2098. // TRUE, falls info mit insert(*,info) in die Struktur
  2099. // aufgenommen wurde.
  2100. // Vorsicht !! nicht aufrufen !!
  2101. // Die Funktion hat einen Aufwand von o(Anzahl der Eintraege) !!
  2102. {  T_PROC("Mapping::is_info");
  2103.    TT(agg_H,T_ENTER);
  2104.  
  2105.    sos_Container  ct = sos_Object_sos_Object_Mapping::make(_tpid,this).container(); 
  2106.    sos_Bool       list_cursor = sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor();
  2107.    sos_Bool       info_based_on_equal = sos_Object_sos_Object_Mapping::make(_tpid,this).get_info_based_on_equal();
  2108.    ht_entry_t  ht_entry;
  2109.    page_t      page;
  2110.    sos_Object  key;
  2111.  
  2112.       // Durchlaufe die gesamte Hashtabelle
  2113.       // benutze jeden Verweis um die Seite zu durchsuchen,
  2114.       // verwende bei mehrfachen Verweisen nur den ersten
  2115.    sos_Int ht_entries = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  2116.    sos_Offset ht_offset = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset();
  2117.    for (sos_Int ht_pos=0;
  2118.         ht_pos < ht_entries; // positiver Abbruch nur in der Schleife
  2119.         ht_pos++)
  2120.    {  ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  2121.    
  2122.          // Wie lautet der dieser Seite zugeordnete Hash-Wert ?
  2123.       sos_Int hash_value_part = (LSHIFT(1,ht_entry.local_depth)-1) 
  2124.                                 BITAND ht_pos;
  2125.    
  2126.          // Ist dieser Verweis der erste auf diese Seite ?
  2127.       if (hash_value_part == ht_pos)
  2128.       {     // Ja, 
  2129.          sos_Offset page_offset = ht_entry.page_list_offset;
  2130.          page_header_t page_header = read_page_header(ct, page_offset);
  2131.    
  2132.          sos_Bool found = FALSE;
  2133.          sos_Int pages = page_header.pages;
  2134.      sos_Int entries_on_last_page = page_header.entries_on_last_page;
  2135.      sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  2136.          for (sos_Int page_no = 1;
  2137.               (page_no<=pages) AND (NOT found);
  2138.               page_no++)
  2139.          {  if (page_no == pages)
  2140.            entries_on_page = entries_on_last_page;
  2141.                 
  2142.             if (entries_on_page > 0)
  2143.                read_page(list_cursor, ct,page_offset, 
  2144.                          entries_on_page, page);
  2145.                
  2146.                // Durchsuche die Seite nach dem Objekt
  2147.             for (sos_Int k=0; 
  2148.                  (NOT found) AND (k<entries_on_page); 
  2149.                  k++)
  2150.             {  key = make_Object(page.entry[k].info);
  2151.                found = agg_same_entity (key,info,info_based_on_equal,EQ_STRONG); 
  2152.         } 
  2153.    
  2154.             if (found) 
  2155.             {  TT(agg_H,T_LEAVE);
  2156.                return TRUE; 
  2157.             } 
  2158.    
  2159.             page_offset = page.page_header.next_page;
  2160.          } 
  2161.       }
  2162.    } 
  2163.  
  2164.    TT(agg_H,T_LEAVE);
  2165.    return FALSE; // Pech ...
  2166. } // ** Mapping::is_info **
  2167.  
  2168. // ************************************************************************** 
  2169. void _sos_Object_sos_Object_Mapping::insert(sos_Typed_id &_tpid,sos_Object Key, sos_Object Entity)
  2170. // ************************************************************************** 
  2171. {  T_PROC("Mapping::insert");
  2172.    TT(agg_H, T_ENTER);
  2173.  
  2174.    sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2175.       // Das Mappingobjekt selbst wird als Methodenausgabe fuer ein ungueltiges 
  2176.       // Objekt benutzt. Drum kann man NO_OBJECT, aber nicht das
  2177.       // Mappingobjekt einfuegen. Soll es auch auch eingefuegt werden koennen, 
  2178.       // benoetigt man ein eigenes MAPPING_NO_OBJECT.
  2179.    if (Key == sos_Object_sos_Object_Mapping::make(_tpid,this))
  2180.       err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
  2181.  
  2182.       // fuege das Element in der Listen-Version hinten an die Liste
  2183.       // in der non-Listen Version haben die beiden letzten Parameter
  2184.       // pred und succ keine Wirkung
  2185.    sos_Object_sos_Object_Mapping::make(_tpid,this).insert_in_list(Key, Entity, sos_Object_sos_Object_Mapping::make(_tpid,this).get_last_object(), my_no_object);
  2186.  
  2187.    TT(agg_H,T_LEAVE);   
  2188. } // ** Mapping::insert **
  2189.  
  2190. // ************************************************************************** 
  2191. void _sos_Object_sos_Object_Mapping::remove (sos_Typed_id &_tpid,sos_Object key)
  2192. // ************************************************************************** 
  2193. {  T_PROC("Mapping::remove");
  2194.  
  2195.    sos_Bool found=FALSE;
  2196.  
  2197.    if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries() >0)
  2198.    {  sos_Container ct = sos_Object_sos_Object_Mapping::make(_tpid,this).container(); 
  2199.       sos_Int org_hash_value = absolute((sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal())?
  2200.                                         key.hash_value():hash_id(key));
  2201.       sos_Int ht_pos         = org_hash_value MOD sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  2202.       ht_entry_t ht_entry = read_ht_entry(ct,sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),ht_pos);
  2203.       found = make_sos_Bool(
  2204.       sos_Object_sos_Object_Mapping::make(_tpid,this).remove_from_page_list (ct, sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(),
  2205.                               sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal(),
  2206.                               ht_entry.page_list_offset, 
  2207.                                   org_hash_value,key));
  2208.       sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2209.       if (found)
  2210.       {     // Versuche, die Seitenliste zu verschmelzen
  2211.          if (sos_Object_sos_Object_Mapping::make(_tpid,this).assemble_page(ht_entry.page_list_offset, 
  2212.                                 ht_entry.local_depth, 
  2213.                                 org_hash_value))
  2214.                // versuche, die Hash-Tabelle zu verkleinern
  2215.             sos_Object_sos_Object_Mapping::make(_tpid,this).decrease_hash_table();
  2216.       }
  2217.    } 
  2218.    TT(agg_H,T_LEAVE; TB(found));
  2219. }// ** Mapping::remove **
  2220.  
  2221. // ************************************************************************** 
  2222. sos_Object _sos_Object_sos_Object_Mapping::__index (sos_Typed_id &_tpid,sos_Object key)
  2223. // ************************************************************************** 
  2224. {  T_PROC("Mapping::operator[]");
  2225.    TT(agg_H,T_ENTER);
  2226.  
  2227.    sos_Object dummy_pred,dummy_succ,info;
  2228.    sos_Container  ct = sos_Object_sos_Object_Mapping::make(_tpid,this).container();
  2229.    sos_Bool       key_based_on_equal = sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal();
  2230.    sos_Bool       list_cursor = sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor();
  2231.    sos_Object     my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2232.    sos_Int        ht_entries = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  2233.    sos_Offset     ht_offset = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset();
  2234.  
  2235.    if (NOT get_entry(ct, list_cursor,key_based_on_equal,ht_entries,
  2236.              ht_offset,key,TRUE, info, dummy_pred,dummy_succ))
  2237.       info = NO_OBJECT;
  2238.  
  2239.    TT(agg_H,T_LEAVE);
  2240.    return info;
  2241. } // ** Mapping::operator[] **
  2242.  
  2243. // ************************************************************************** 
  2244. sos_Object _sos_Object_sos_Object_Mapping::get_key(sos_Typed_id &_tpid,sos_Cursor c)
  2245. // ************************************************************************** 
  2246. {  T_PROC("Mapping::get_key(sos_Cursor)");
  2247.    TT(agg_H, T_ENTER);
  2248.  
  2249.    err_assert (c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this)), "Mapping:get_key");
  2250.    err_assert (sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid(c), "Mapping:get_key");
  2251.  
  2252.    sos_Map_node mn = sos_Map_node::make (c.get_current());
  2253.    sos_Object   o  = mn.get_key_val();
  2254.  
  2255.    TT(agg_H,T_LEAVE);
  2256.    return o;
  2257. } // ** Mapping::get_key **
  2258.  
  2259. // ************************************************************************** 
  2260. sos_Object _sos_Object_sos_Object_Mapping::get_info(sos_Typed_id &_tpid,sos_Cursor c)
  2261. // ************************************************************************** 
  2262. {  T_PROC("Mapping::get_info(sos_Cursor)");
  2263.    TT(agg_H, T_ENTER);
  2264.  
  2265.    err_assert (c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this)), "Mapping:get_info");
  2266.    err_assert(sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid(c),"Mapping:get_info");
  2267.  
  2268.    sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2269.    sos_Object dummy_pred,
  2270.           dummy_succ;
  2271.  
  2272.    sos_Object key = sos_Map_node::make (c.get_current()).get_key_val();
  2273.    sos_Object info;
  2274.    sos_Bool found = get_entry(sos_Object_sos_Object_Mapping::make(_tpid,this).container(), sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(),
  2275.                               sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal(),
  2276.                               sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries(), sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(), 
  2277.                               key,TRUE, info,dummy_pred,dummy_succ);
  2278.       // Beliebter Benutzerfehler: Ein Prozess erzeugt
  2279.       // einen Eintrag mit einem Key im TEMP_CONTAINER, das
  2280.       // Programm beendet, ein anderer Prozess versucht darueber
  2281.       // zu itterieren. Trotz das im Key Bockmist steht, kann er
  2282.       // noch mit get_key geliefert werden. Wenn jedoch der passende Eintrag 
  2283.       // dazu gesucht wird, wird der Hashwert vom Key gebraucht. In diesem
  2284.       // stehen wilde Sachen, der Eintrag wird (vermutlich) nicht gefunden.
  2285.    if (NOT found)
  2286.       err_raise(err_USE,"Entry didn't exists anymore","Mapping::get_info");
  2287.  
  2288.    TT(agg_H, T_LEAVE);
  2289.    return info;
  2290. } // ** Mapping::get_info **
  2291.  
  2292. // ************************************************************************** 
  2293. void _sos_Object_sos_Object_Mapping::set_info(sos_Typed_id &_tpid,sos_Cursor c, sos_Object o)
  2294. // ************************************************************************** 
  2295. {  T_PROC ("Mapping::set_info");
  2296.    TT (agg_H, T_ENTER);
  2297.  
  2298.    err_assert ((c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this))), "Mapping:set_info");
  2299.    sos_Object_sos_Object_Mapping::make(_tpid,this).insert (sos_Map_node::make (c.get_current()).get_key_val(), o);
  2300.  
  2301.    TT (agg_H, T_LEAVE);
  2302. } // ** Mapping::set_info **
  2303.  
  2304. // ************************************************************************** 
  2305. void _sos_Object_sos_Object_Mapping::move_cursor(sos_Typed_id &_tpid,sos_Cursor c, sos_Object key)
  2306. // ************************************************************************** 
  2307. // sets the cursor c to the key object in the mapping that corresponds
  2308. // to the given key
  2309. {  T_PROC ("Mapping::move_cursor");
  2310.    TT( agg_H, T_ENTER);
  2311.  
  2312.    err_assert (c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this)), "Mapping:move_cursor");
  2313.    err_assert (sos_Object_sos_Object_Mapping::make(_tpid,this).is_key(key), "Mapping:move_cursor");
  2314.  
  2315.    sos_Object dummy_pred, dummy_succ, dummy_info;
  2316.    sos_Bool found = get_entry(sos_Object_sos_Object_Mapping::make(_tpid,this).container(), sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(),
  2317.                               sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal(),
  2318.                               sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries(),sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),
  2319.                               key,FALSE, dummy_info, dummy_pred,dummy_succ);
  2320.    err_assert (found, "Mapping:move_cursor");
  2321.    sos_Map_node::make (c.get_current()).set_key_val(key); 
  2322.  
  2323.    TT(agg_H, T_LEAVE);
  2324. } // ** Mapping::move_cursor **
  2325.  
  2326. // ************************************************************************** 
  2327. void _sos_Object_sos_Object_Mapping::insert_before (sos_Typed_id &_tpid,sos_Cursor c,
  2328.                                                    sos_Object Key,
  2329.                                                    sos_Object Entity)
  2330. // ************************************************************************** 
  2331. {  T_PROC("Mapping::insert_before");
  2332.    TT(agg_H, T_ENTER);
  2333.  
  2334.    err_assert (sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(), "Mapping:insert_before");
  2335.    err_assert (c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this)), "Mapping:insert_before");
  2336.    err_assert (sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid(c), "Mapping:insert_before");
  2337.  
  2338.    if (Key == sos_Object_sos_Object_Mapping::make(_tpid,this))
  2339.       err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
  2340.    sos_Map_node mn = sos_Map_node::make (c.get_current());
  2341.  
  2342.    sos_Object dummy_info,pred,dummy_succ;
  2343.    sos_Object key = mn.get_key_val();
  2344.    get_entry(sos_Object_sos_Object_Mapping::make(_tpid,this).container(), sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(), 
  2345.              sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal(),
  2346.              sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries(),sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),
  2347.              key,FALSE, dummy_info, pred,dummy_succ);
  2348.    sos_Object_sos_Object_Mapping::make(_tpid,this).insert_in_list(Key, Entity, pred, mn.get_key_val());
  2349.  
  2350.    TT(agg_H, T_LEAVE);
  2351. } // ** Mapping::insert_before **
  2352.  
  2353. // ************************************************************************** 
  2354. void _sos_Object_sos_Object_Mapping::insert_after (sos_Typed_id &_tpid,sos_Cursor c,
  2355.                                                   sos_Object Key,
  2356.                                                   sos_Object Entity)
  2357. // ************************************************************************** 
  2358. {  T_PROC("Mapping::insert_after");
  2359.    TT(agg_H, T_ENTER);
  2360.  
  2361.    err_assert (sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(), "Mapping:insert_after");
  2362.    err_assert (c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this)), "Mapping:insert_after");
  2363.    err_assert (sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid(c), "Mapping:insert_after");
  2364.  
  2365.    if (Key == sos_Object_sos_Object_Mapping::make(_tpid,this))
  2366.       err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
  2367.  
  2368.    sos_Map_node mn = sos_Map_node::make (c.get_current());
  2369.  
  2370.    sos_Object dummy_info,dummy_pred,succ;
  2371.    sos_Object key = mn.get_key_val();
  2372.    get_entry(sos_Object_sos_Object_Mapping::make(_tpid,this).container(), sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(), 
  2373.              sos_Object_sos_Object_Mapping::make(_tpid,this).get_key_based_on_equal(),
  2374.              sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries(),sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),
  2375.              key,FALSE,dummy_info,dummy_pred,succ);
  2376.    sos_Object_sos_Object_Mapping::make(_tpid,this).insert_in_list(Key, Entity, mn.get_key_val(), succ);
  2377.  
  2378.    TT(agg_H, T_LEAVE);
  2379. } // ** Mapping::insert_after **
  2380.  
  2381. // ************************************************************************** 
  2382. void _sos_Object_sos_Object_Mapping::local_assign
  2383.                                        (sos_Object_sos_Object_Mapping x,
  2384.                                         sos_Object                    o)
  2385. // ************************************************************************** 
  2386. {  T_PROC("Mapping::local_assign");
  2387.  
  2388.    sos_Object_sos_Object_Mapping y = sos_Object_sos_Object_Mapping::make (o);
  2389.    sos_Container y_ct = y.container();
  2390.    sos_Container x_ct = x.container();
  2391.    sos_Bool x_list_cursor = x.get_list_cursor();
  2392.    
  2393.    err_assert ((y.get_list_cursor() == x_list_cursor),
  2394.                "Mapping::local_assign");
  2395.  
  2396.    destroy_ht(x_list_cursor, x_ct, x.get_ht_entries(),
  2397.               x.get_global_depth(), x.get_ht_offset());
  2398.  
  2399.    sos_Bool key_based_on_equal = y.get_key_based_on_equal();
  2400.    sos_Bool info_based_on_equal= y.get_info_based_on_equal();
  2401.    sos_Int cardinality         = y.get_cardinality();
  2402.    sos_Int no_of_pages         = y.get_no_of_pages();
  2403.    sos_Int no_of_page_lists    = y.get_no_of_page_lists();
  2404.    sos_Int global_depth        = y.get_global_depth();
  2405.    sos_Int ht_entries          = y.get_ht_entries();
  2406.    sos_Int no_of_pages_offset  = y.get_no_of_pages_offset();
  2407.  
  2408.    x.set_key_based_on_equal(key_based_on_equal);
  2409.    x.set_info_based_on_equal(info_based_on_equal);
  2410.    x.set_cardinality(cardinality);
  2411.    x.set_no_of_pages(no_of_pages);
  2412.    x.set_no_of_page_lists(no_of_page_lists);
  2413.    x.set_global_depth(global_depth);
  2414.    x.set_ht_entries(ht_entries);
  2415.    x.set_first_object(y.get_first_object());
  2416.    x.set_last_object(y.get_last_object());
  2417.  
  2418.  
  2419.    if (cardinality != 0)
  2420.    {    // kopiere das Feld fuer no_of_pages rueber
  2421.       sos_Offset new_no_of_pages_offset = x_ct.allocate(NO_OF_PAGES_ARRAY_SIZE);
  2422.       x.set_no_of_pages_offset(new_no_of_pages_offset);
  2423.       sos_Char mem [NO_OF_PAGES_ARRAY_SIZE];
  2424.       y_ct.read(no_of_pages_offset, NO_OF_PAGES_ARRAY_SIZE, &mem);
  2425.       x_ct.write(new_no_of_pages_offset, NO_OF_PAGES_ARRAY_SIZE, &mem);
  2426.   
  2427.          // erzeuge die Hashtabelle
  2428.       x.set_ht_offset(x_ct.allocate(y.get_ht_entries() *HT_ENTRY_SIZE));
  2429.          // Laufe die erste HT durch und kopiere die Seiten
  2430.       sos_Offset old_ht_offset = y.get_ht_offset();
  2431.       sos_Offset new_ht_offset = x.get_ht_offset();
  2432.       for (sos_Int ht_pos = 0;ht_pos<y.get_ht_entries();ht_pos++)
  2433.       {  ht_entry_t ht_entry = read_ht_entry(y_ct,old_ht_offset,ht_pos);
  2434.    
  2435.             // Ist es der erste Zeiger auf die Seitenliste ?
  2436.          sos_Int local_depth = ht_entry.local_depth;
  2437.          sos_Int first_link = FIRST_LINK(ht_pos, local_depth);
  2438.          if (first_link == ht_pos)
  2439.          {     // erster Verweis, kopiere die Seitenliste
  2440.             sos_Offset old_page_offset = ht_entry.page_list_offset;
  2441.             page_header_t  old_first_page_header = 
  2442.                 read_page_header(y_ct, ht_entry.page_list_offset);
  2443.    
  2444.             sos_Offset pred_page_offset=0;
  2445.    
  2446.             for(sos_Int page_no=1;page_no<=old_first_page_header.pages;page_no++)
  2447.             {  sos_Offset new_page_offset = 
  2448.           x_ct.allocate(PAGE_SIZE(x_list_cursor));
  2449.                if (page_no == 1)
  2450.                   ht_entry.page_list_offset = new_page_offset;
  2451.                else
  2452.                {  page_header_t tmp_page_header = old_first_page_header;
  2453.                   tmp_page_header.next_page = new_page_offset;
  2454.                   // schreibe den Seitenverweis in den Vorgaenger
  2455.                   write_page_header(x_ct,pred_page_offset, tmp_page_header);
  2456.                }
  2457.    
  2458.                page_t tmp_page;
  2459.                sos_Int entries = (page_no < old_first_page_header.pages)?
  2460.                                  MAX_PAGE_ENTRIES(x_list_cursor):
  2461.                                  old_first_page_header.entries_on_last_page;
  2462.  
  2463.                   // kopiere die Seite
  2464.                read_page(x_list_cursor,y_ct,old_page_offset,entries,tmp_page);
  2465.                write_page(x_list_cursor, x_ct,new_page_offset,
  2466.                           MAX_PAGE_ENTRIES(x_list_cursor), tmp_page);
  2467.                pred_page_offset = new_page_offset;
  2468.    
  2469.                   // lese den Seitenkopf der Seite, um 
  2470.           // Nachfolgerseite rauszufinden
  2471.                page_header_t old_page_header = 
  2472.                   read_page_header(y_ct,old_page_offset);
  2473.                
  2474.                old_page_offset = old_page_header.next_page;
  2475.             } // kopiere alle Seiten
  2476.    
  2477.                // schreibe den HT-Eintrag in alle Verweise der HT
  2478.             sos_Int no_of_links = LSHIFT(1,global_depth-local_depth);
  2479.             for (sos_Int k=0;k<no_of_links;k++)
  2480.             {  sos_Int x = LSHIFT(k,local_depth);
  2481.                sos_Int other_link = x BITOR ht_pos;
  2482.                write_ht_entry(x_ct,new_ht_offset,other_link,ht_entry);
  2483.             } // schreibe alle HT-Eintraege pro Seite
  2484.          } 
  2485.       } 
  2486.       if (x_list_cursor)
  2487.       {  sos_Object my_no_object = x;
  2488.          x.write_succ_pred
  2489.             (x_ct, key_based_on_equal, x_list_cursor, 
  2490.              x.get_first_object(), FALSE, my_no_object);
  2491.          x.write_succ_pred
  2492.             (x_ct, key_based_on_equal, x_list_cursor,  
  2493.              x.get_last_object(), TRUE, my_no_object);
  2494.       }
  2495.    }
  2496.    else
  2497.    {     // Kein Element drin, erzeuge nichts, initialisere wie in local_init
  2498.       sos_Object my_no_object = x;
  2499.       x.set_first_object(my_no_object);
  2500.       x.set_last_object(my_no_object);
  2501.       x.set_ht_offset(NIL);
  2502.       x.set_ht_entries(0);
  2503.       x.set_no_of_pages_offset(NIL);
  2504.    }
  2505.  
  2506.    TT(agg_H,T_LEAVE); 
  2507. } // ** Mapping::local_assign **
  2508.  
  2509. // ************************************************************************** 
  2510. sos_Bool _sos_Object_sos_Object_Mapping::local_equal
  2511.                                        (sos_Object_sos_Object_Mapping x,
  2512.                                         sos_Object                    o,
  2513.                                         sos_Eq_kind                   eq_kind) 
  2514. // ************************************************************************** 
  2515. {  sos_Bool result;
  2516.  
  2517.    if ((eq_kind EQ EQ_STRONG AND NOT o.has_type(x.type())) OR
  2518.        (eq_kind EQ EQ_WEAK   AND NOT o.isa     (x.type())))
  2519.       result = FALSE;
  2520.    else
  2521.    {  sos_Object_sos_Object_Mapping y = 
  2522.          sos_Object_sos_Object_Mapping::make (o);
  2523.       if (y.get_cardinality() != x.get_cardinality())
  2524.          result = FALSE; 
  2525.       else
  2526.       {  sos_Bool info_based_on_equal = x.get_info_based_on_equal();
  2527.          agg_iterate_association (x, sos_Object key, sos_Object info)
  2528.          {  if (NOT agg_same_entity (y[key],info,info_based_on_equal,eq_kind))
  2529.             {  result = FALSE;
  2530.                break;
  2531.             }
  2532.          } 
  2533.          agg_iterate_association_end (x, key, info);
  2534.       }
  2535.    }
  2536.  
  2537.    return result;
  2538. } // ** Mapping::local_equal **
  2539.  
  2540. // ************************************************************************** 
  2541. sos_Int _sos_Object_sos_Object_Mapping::local_hash_value
  2542.                                        (sos_Object_sos_Object_Mapping m)
  2543. // ************************************************************************** 
  2544. // Ansich muesste der augenblickliche Hashwert gespeichert werden, und bei 
  2545. // jedem eingefuegten Element mit einer reversiblen Operation verknuepft 
  2546. // werden. Bei jedem remove, muss diese reversible Operation aufgerufen 
  2547. // werden. Zu viel Aufwand, drum bisher noch nicht implementiert.
  2548. {  return m.card();
  2549. } // ** Mapping::local_hash_value **
  2550.  
  2551. // ************************************************************************** 
  2552. sos_Int _sos_Object_sos_Object_Mapping::size(sos_Typed_id &_tpid)
  2553. // ************************************************************************** 
  2554. {  sos_Int o_size = _sos_Object::size(_tpid);
  2555.    sos_Int ht_size = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries() * HT_ENTRY_SIZE;
  2556.    sos_Int nop_size = (ht_size>0)?NO_OF_PAGES_ARRAY_SIZE:0;
  2557.    sos_Int pg_size = sos_Object_sos_Object_Mapping::make(_tpid,this).get_no_of_pages()*PAGE_SIZE(sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor());
  2558.    return o_size +
  2559.           sos_Object_sos_Object_Mapping::make(_tpid,this).container().rounded (ht_size) +
  2560.           sos_Object_sos_Object_Mapping::make(_tpid,this).container().rounded (pg_size) +
  2561.           sos_Object_sos_Object_Mapping::make(_tpid,this).container().rounded (nop_size);
  2562. } // ** Mapping::size **
  2563.  
  2564. // **************************************************************************
  2565. sos_Bool _sos_Object_sos_Object_Mapping::is_role1 (sos_Typed_id &_tpid,sos_Object key)
  2566. // **************************************************************************
  2567. {  return sos_Object_sos_Object_Mapping::make(_tpid,this).is_key (key);
  2568. } // ** Mapping::is_role1 **
  2569.  
  2570. // **************************************************************************
  2571. sos_Bool _sos_Object_sos_Object_Mapping::is_role2 (sos_Typed_id &_tpid,sos_Object info)
  2572. // **************************************************************************
  2573. {  return sos_Object_sos_Object_Mapping::make(_tpid,this).is_info (info);
  2574. } // ** Mapping::is_role2 **
  2575.  
  2576. // **************************************************************************
  2577. sos_Object _sos_Object_sos_Object_Mapping::get_role1 (sos_Typed_id &_tpid,sos_Cursor c)
  2578. // **************************************************************************
  2579. {  return sos_Object_sos_Object_Mapping::make(_tpid,this).get_key (c);
  2580. } // ** Mapping::get_role1 **
  2581.  
  2582. // **************************************************************************
  2583. sos_Object _sos_Object_sos_Object_Mapping::get_role2 (sos_Typed_id &_tpid,sos_Cursor c)
  2584. // **************************************************************************
  2585. {  return sos_Object_sos_Object_Mapping::make(_tpid,this).get_info (c);
  2586. } // ** Mapping::get_role2 **
  2587.  
  2588. // ************************************************************************** 
  2589. void _sos_Object_sos_Object_Mapping::remove_at(sos_Typed_id &_tpid,sos_Cursor c)
  2590. // ************************************************************************** 
  2591. {  T_PROC("Mapping::remove_at");
  2592.    TT(agg_H, T_ENTER);
  2593.  
  2594.    err_assert (c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this)), "Mapping:remove_at");
  2595.    err_assert (sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid(c), "Mapping:remove_at");
  2596.  
  2597.    sos_Object key = sos_Object_sos_Object_Mapping::make(_tpid,this).get_key(c);
  2598.  
  2599.    if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor())
  2600.       sos_Object_sos_Object_Mapping::make(_tpid,this).to_succ(c);
  2601.    else
  2602.    {     // Setze Cursor auf my_no_object => is_valid == FALSE
  2603.       sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2604.       sos_Map_node mn = sos_Map_node::make (c.get_current());
  2605.       mn.set_key_val(my_no_object);
  2606.    }
  2607.  
  2608.    sos_Object_sos_Object_Mapping::make(_tpid,this).remove(key);
  2609.  
  2610.    TT(agg_H, T_LEAVE);
  2611. } // ** Mapping::remove_at **
  2612.  
  2613. // ************************************************************************** 
  2614. void _sos_Object_sos_Object_Mapping::clear(sos_Typed_id &_tpid)
  2615. // ************************************************************************** 
  2616. {  T_PROC("Mapping::clear");
  2617.    TT(agg_H, T_ENTER);
  2618.    
  2619.    sos_Container ct = sos_Object_sos_Object_Mapping::make(_tpid,this).container();
  2620.    sos_Int ht_entries = sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries();
  2621.    if (ht_entries >0)
  2622.       destroy_ht(sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor(), ct, ht_entries,
  2623.                  sos_Object_sos_Object_Mapping::make(_tpid,this).get_global_depth(), sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset());
  2624.  
  2625.    sos_Object my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2626.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_first_object(my_no_object);
  2627.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_last_object(my_no_object);
  2628.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_cardinality (0);
  2629.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_ht_entries(0);
  2630.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_global_depth(0);
  2631.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages_offset(NIL);
  2632.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_no_of_pages(0);
  2633.    sos_Object_sos_Object_Mapping::make(_tpid,this).set_ht_offset(NIL);
  2634.  
  2635.    TT(agg_H, T_LEAVE);
  2636. } // ** Mapping::clear **
  2637.  
  2638. // **************************************************************************
  2639. sos_Int _sos_Object_sos_Object_Mapping::card (sos_Typed_id &_tpid)
  2640. // **************************************************************************
  2641. {  T_PROC ("Mapping::card");
  2642.    TT (agg_H, T_ENTER);
  2643.  
  2644.    sos_Int crd = sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality();
  2645.  
  2646.    TT (agg_H, T_LEAVE);
  2647.    return crd;
  2648. } // ** Mapping::card **
  2649.  
  2650. // ************************************************************************** 
  2651. sos_Cursor _sos_Object_sos_Object_Mapping::open_cursor(sos_Typed_id &_tpid,sos_Container Cursor_ct)
  2652. // ************************************************************************** 
  2653. {  T_PROC ("Mapping::open_cursor");
  2654.    TT( agg_H, T_ENTER);
  2655.  
  2656.    sos_Cursor c = sos_Cursor::create(Cursor_ct, sos_Object_sos_Object_Mapping::make(_tpid,this));
  2657.    sos_Map_node mn = sos_Map_node::create(Cursor_ct);
  2658.    c.set_current(mn);
  2659.  
  2660.    sos_Object_sos_Object_Mapping::make(_tpid,this).to_first(c);
  2661.  
  2662.    TT(agg_H, T_LEAVE);
  2663.    return c;
  2664. } // ** Mapping::open_cursor **
  2665.  
  2666. // ************************************************************************** 
  2667. void _sos_Object_sos_Object_Mapping::close_cursor(sos_Typed_id &_tpid,sos_Cursor c)
  2668. // ************************************************************************** 
  2669. {  err_assert ((c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this))), "Mapping:close_cursor");
  2670.    c.get_current().destroy(); 
  2671.    c.destroy(); 
  2672. } // ** Mapping::close_cursor **
  2673.  
  2674. // ************************************************************************** 
  2675. sos_Cursor _sos_Object_sos_Object_Mapping::duplicate(sos_Typed_id &_tpid,sos_Cursor c)
  2676. // ************************************************************************** 
  2677. {  err_assert ((c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this))), "Mapping:duplicate");
  2678.    sos_Container Cursor_ct = c.container();
  2679.  
  2680.    sos_Cursor dup_c = sos_Cursor::create(Cursor_ct, sos_Object_sos_Object_Mapping::make(_tpid,this));
  2681.    sos_Map_node dup_mn = sos_Map_node::create(Cursor_ct);
  2682.  
  2683.    dup_c.set_current (dup_mn);
  2684.    dup_mn.set_key_val (sos_Map_node::make (c.get_current()).get_key_val());
  2685.  
  2686.    return dup_c;
  2687. } // ** Mapping::duplicate **
  2688.  
  2689. // **************************************************************************
  2690. sos_Bool _sos_Object_sos_Object_Mapping::is_valid (sos_Typed_id &_tpid,sos_Cursor c)
  2691. // **************************************************************************
  2692. {  sos_Map_node mn           = sos_Map_node::make (c.get_current());
  2693.    sos_Object   my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2694.    sos_Bool     valid        = (mn.get_key_val() != my_no_object);
  2695.  
  2696.    return valid;
  2697. } // ** is_valid **
  2698.  
  2699. // ************************************************************************** 
  2700. sos_Bool _sos_Object_sos_Object_Mapping::to_first(sos_Typed_id &_tpid,sos_Cursor c)
  2701. // ************************************************************************** 
  2702. {  err_assert ((c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this))), "Mapping:to_first");
  2703.    sos_Container Cursor_ct = c.container();
  2704.    sos_Map_node  current = sos_Map_node::make (c.get_current());
  2705.    sos_Object    my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2706.    sos_Object    first;
  2707.  
  2708.    if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality() > 0)
  2709.    {  if (NOT (sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor()))
  2710.          first = read_first_object(sos_Object_sos_Object_Mapping::make(_tpid,this).container(),sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),
  2711.                                    sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality(),my_no_object);
  2712.       else
  2713.          first = sos_Object_sos_Object_Mapping::make(_tpid,this).get_first_object();
  2714.    }
  2715.    else
  2716.       first = my_no_object;
  2717.    
  2718.    current.set_key_val(first);
  2719.  
  2720.    return sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid(c);
  2721. } // ** Mapping::to_first **
  2722.  
  2723. // ************************************************************************** 
  2724. sos_Bool _sos_Object_sos_Object_Mapping::to_last(sos_Typed_id &_tpid,sos_Cursor c)
  2725. // ************************************************************************** 
  2726. {  err_assert ((c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this))), "Mapping:to_last");
  2727.    sos_Map_node  current      = sos_Map_node::make (c.get_current());
  2728.    sos_Container Cursor_ct    = c.container();
  2729.    sos_Object    my_no_object = sos_Object_sos_Object_Mapping::make(_tpid,this);
  2730.    sos_Object    last;
  2731.  
  2732.    if (sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality() > 0)
  2733.    {  if (NOT (sos_Object_sos_Object_Mapping::make(_tpid,this).get_list_cursor()))
  2734.          last = read_last_object
  2735.                    (sos_Object_sos_Object_Mapping::make(_tpid,this).container(),
  2736.                     sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_offset(),sos_Object_sos_Object_Mapping::make(_tpid,this).get_cardinality(),
  2737.                     my_no_object,sos_Object_sos_Object_Mapping::make(_tpid,this).get_ht_entries());
  2738.       else
  2739.          last = sos_Object_sos_Object_Mapping::make(_tpid,this).get_last_object();
  2740.    }      
  2741.    else
  2742.       last = my_no_object;
  2743.  
  2744.    current.set_key_val(last);
  2745.  
  2746.    return sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid(c);
  2747. } // ** Mapping::to_last **
  2748.  
  2749. // ************************************************************************** 
  2750. sos_Bool _sos_Object_sos_Object_Mapping::to_succ(sos_Typed_id &_tpid,sos_Cursor c, Index i) 
  2751. // ************************************************************************** 
  2752. {  err_assert (c.defined_for (sos_Object_sos_Object_Mapping::make(_tpid,this)), "Mapping:to_succ");
  2753.    err_assert (sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid(c), "Mapping:to_succ");
  2754.  
  2755.    sos_Map_node mn = sos_Map_node::make (c.get_current());
  2756.    sos_Object   o  = sos_Object_sos_Object_Mapping::make(_tpid,this).search_succ_pred (mn.get_key_val(),i);
  2757.  
  2758.    mn.set_key_val (o); 
  2759.  
  2760.    return sos_Object_sos_Object_Mapping::make(_tpid,this).is_valid (c);
  2761. } // ** Mapping::to_succ **
  2762.  
  2763. // ************************************************************************** 
  2764. sos_Bool _sos_Object_sos_Object_Mapping::to_pred(sos_Typed_id &_tpid,sos_Cursor c, Index i)
  2765. // ************************************************************************** 
  2766. {  return sos_Object_sos_Object_Mapping::make(_tpid,this).to_succ(c,-i); 
  2767. } // ** Mapping::to_pred **
  2768.